如何在两个 React 组件之间创建共享状态?

IT技术 javascript reactjs react-router
2021-02-08 01:31:57

我有 2 个需要共享状态的 react 组件,react-router 显示组件 A,它接受一些输入并将其添加到其状态,在成功更新状态后,我想重定向到组件 B,用户添加在我向我的 api 提交发布请求以保存来自组件 A 和 B 的数据之前,我需要更多的输入并更新与组件 A 相同的状态,以使用来自 A 和 B 的输入构建一个对象。我该如何实现这一点,是否有使用 react-router 的方法,还是必须在组件之间建立父/子关系?

5个回答

组件之间的依赖类型将定义最佳方法。

例如,如果您计划拥有一个中央存储,redux 是一个不错的选择。然而,其他方法也是可能的:

  • 父母对孩子

    1. props
    2. 实例方法
  • 孩子对父母

    1. 回调函数
    2. 事件冒泡
  • 兄妹对兄妹

    1. 父组件
  • 任何对任何

    1. 观察者模式
    2. 全局变量
    3. 语境

在此处找到有关每种方法的更多详细信息

您想要的是实现一些存储您的状态的对象,可以使用回调函数对其进行修改。然后你可以将这些函数传递给你的 React 组件。

例如,您可以创建一个商店:

function Store(initialState = {}) {
  this.state = initialState;
}
Store.prototype.mergeState = function(partialState) {
  Object.assign(this.state, partialState);
};

var myStore = new Store();

ReactDOM.render(
  <FirstComponent mergeState={myStore.mergeState.bind(myStore)} />,
  firstElement
  );
ReactDOM.render(
  <SecondComponent mergeState={myStore.mergeState.bind(myStore)} />,
  secondElement
  );

现在,FirstComponentSecondComponent实例都可以调用this.props.mergeState({ . . .})将状态分配给同一个存储。

我留给Store.prototype.getState读者作为练习。

请注意,您始终可以将 store ( myStore) 本身传递给组件;这样做只是感觉不那么react。

以下是一些您可能感兴趣的文档:

React Docs:“组件之间的通信”

对于没有父子关系的两个组件之间的通信,您可以设置自己的全局事件系统。在 componentDidMount() 中订阅事件,在 componentWillUnmount() 中取消订阅,并在收到事件时调用 setState()。通量模式是一种可能的安排方式。

@CoreyAlix 您能否更清楚地了解您提出的方案?什么是“全局父级”,子级“引用全局父级”是什么意思?如果您要问为什么在两个节点的公共父节点上存储状态并不总是可行,这可以分为两个独立的问题:(1) 总是找到或创建一个公共父节点;(2) 以一种非意大利面的方式将信息从一个共同的父级传递给相关的子级。
2021-03-25 01:31:57
该参考链接重定向到其他地方。
2021-03-26 01:31:57
我想知道为什么香草存储解决方案与反应状态组件,是的。反应状态可用于绑定到子项的属性,因此设置父项-> 子项绑定。属性之一可能是父/状态设置器本身,就像在您提出的解决方案中一样,允许子项设置“全局”状态,并且两个子项的绑定属性都将刷新。我并不是说我知道得更好,我很好奇为什么香草解决方案更有意义?
2021-03-31 01:31:57
在这里反应初学者:我很好奇为什么人为地将父母引入孩子与孩子的关系是不切实际的。两个孩子被实例化的地方难道不是一个可以引用全局父级并共享其状态的地方,就像共享 myStore 一样吗?
2021-04-03 01:31:57
@CoreyAlix (2) 是关键。我认为这是为工作选择正确的工具:当 React 组件代表的节点和它们创建的信息渠道遵循/简化应用程序的概念形状时,它们才有意义。当您开始引入临时节点和属性以响应概念模型中出现的新共享状态时,它可能会变成一个毛球!但是,如果您只是问“为什么使用普通对象而不是‘全局状态持有者’ React 组件?”:我可以想象两种方法都有优势的情况。
2021-04-08 01:31:57

在多个组件之间使用共享状态而不将应用程序的代码重写到某个状态管理系统的最简单方法是use-between钩子。

在代码沙盒中试试这个例子

import React, { useState } from "react";
import { useBetween } from "use-between";

// Make a custom hook with your future shared state
const useFormState = () => {
  const [username, setUsername] = useState("");
  const [email, setEmail] = useState("");
  return {
    username, setUsername, email, setEmail
  };
};

// Make a custom hook for sharing your form state between any components
const useSharedFormState = () => useBetween(useFormState);

const ComponentA = () => {
  // Use the shared hook!
  const { username, setUsername } = useSharedFormState();
  return (
    <p>
      Username: <input value={username} onChange={(ev) => setUsername(ev.target.value)} />
    </p>
  );
};

const ComponentB = () => {
  // Use  the shared hook!
  const { email, setEmail } = useSharedFormState();
  return (
    <p>
      Email: <input value={email} onChange={(ev) => setEmail(ev.target.value)} />
    </p>
  );
};

const ComponentC = () => {
  // Use shared hook!
  const { email, username } = useSharedFormState();
  return (
    <p>
      Username: {username} <br />
      Email: {email}
    </p>
  );
};

export const App = () => (
  <>
    <ComponentA />
    <ComponentB />
    <ComponentC />
  </>
);
  • 首先,我们创建useFormState自定义钩子作为我们状态的来源。
  • 在下一步中,我们创建在内部useSharedFormState使用useBetween钩子的钩子。该钩子可用于任何可以读取或更新共享状态的组件!
  • 最后一步是useSharedFormState在我们的组件中使用。

useBetween是一种调用任何钩子的方法。但是这样状态就不会存储在 React 组件中。对于同一个钩子,调用的结果是一样的。所以我们可以在不同的组件中调用一个钩子并在一种状态上协同工作。当更新共享状态时,使用它的每个组件也将被更新。

您可以设置父子关系,然后可以将数据作为props传递给子组件。

否则,如果您想在与任何一个(父/子)无关的 2 个组件之间创建交互,您可以检查通量或更好的redux

我会说你应该使用 redux。看这里为什么

您可以构建自定义 React 钩子以state在组件之间共享一个,我在这里做了一个您可以通过下载use-linked-state.js文件来使用它

导入useStateGatewayhook 后,在父组件中声明网关并将其传递给您的子组件

import {useStateGateway} from "use-linked-state";
const myGateway = useStateGateway({partA:null, partB:null});
return (
  <>
    <ComponentA gateway={myGateway}>
    <ComponentB gateway={myGateway}>
    <ComponentPost gateWay={myGateway}>
  </>
  )

然后您可以通过自定义 useLinkedState 钩子访问这三个组件之间的共享状态

import { useLinkedState } from "use-linked-state";

export default function ComponentA({gateway}){

  const [state, setState] =  useLinkedState(gateway);

  <your logic>

}

在你的逻辑ComponentAComponentB共享对象中会负责自己的部分{partA:"filled by ComponentA", partB:"filled by componentB"}最后ComponentPost发布的结果,如果partApartB共享对象是有效的。

通过这种方式,您可以组合组件并在它们之间建立连接以相互通信。