【问题标题】:Using useReducer to dispatch action from one child component and update state in another child component使用 useReducer 从一个子组件调度操作并在另一个子组件中更新状态
【发布时间】:2020-03-07 17:20:30
【问题描述】:

这是一个 CodeSandbox,其中包含以下示例代码,linter 突出显示了一些问题:https://codesandbox.io/s/react-repl-bw2h1

下面是我正在尝试做的一个基本示例。在容器组件中,我有一个上下文AppContext,它为子组件<ChildConsumer /><ChildDispatcher /> 提供状态。

<ChildConsumer /> 组件正在使用useContext 接收此状态,这似乎按预期工作。

<ChildDispatcher /> 中,我试图在单击按钮时调度一个动作。为此,我创建了一个处理动作的减速器reducer。我还在此处设置了 useReducer,它接收 reducer 和初始 store 状态。

当我点击按钮时,什么也没有发生。我期望发生的是dispatch 接收从useReducer 拉出的state 以及action 对象,并将它们传递给reducer。 reducer 应该看到BUTTON_CLICKED 类型的动作被接收,并且应该返回一个包含旧状态的新状态以及一个额外的'goodbye' 项。然后,子组件<ChildConsumer /> 应该使用这个新状态重新渲染。

import React, { createContext, useContext, useReducer } from "react";
import ReactDOM from "react-dom";

const store = [""];
const AppContext = createContext(store);

const ChildDispatcher = () => {
  const reducer = (state, action) => {
    switch (action.type) {
      case "BUTTON_CLICKED":
        return [...state, "goodbye"];
      default:
        return state;
    }
  };

  const [state, dispatch] = useReducer(reducer, store);
  const handleClick = () =>
    dispatch(state, {
      type: "BUTTON_CLICKED"
    });
  return <button onClick={handleClick}>press me</button>;
};

const ChildConsumer = () => {
  const [consumer] = useContext(AppContext);
  return <div>{consumer}</div>;
};

const App = () => {
  return (
    <div>
      <h1>Using Context and useReducer</h1>
      <AppContext.Provider value={["hello"]}>
        <ChildConsumer />
        <ChildDispatcher />
      </AppContext.Provider>
    </div>
  );
};

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

【问题讨论】:

  • 你将如何真正重构它以将每个孩子放在自己的文件中?

标签: javascript reactjs react-redux react-hooks use-reducer


【解决方案1】:

我对你的代码做了一个小修改。

您必须像下面这样传递调度。 Dispatch 需要一个 object 类型的参数。

const handleClick = () => dispatch({ type: "BUTTON_CLICKED" });

然后可以像这样访问这个状态。

const ChildDispatcher = () => {
  const reducer = (state, action) => {
    switch (action.type) {
      case "BUTTON_CLICKED":
        //action.state      // like this
        return [...state, "goodbye"];
      default:
        return state;
    }
  };

  const [state, dispatch] = useReducer(reducer, store);
  const handleClick = () =>
    dispatch(state, {
      type: "BUTTON_CLICKED"
    });
  return <button onClick={handleClick}>press me</button>;
};

默认情况下,react 会将状态传递给调度程序。但是如果您想传递一些数据,您可以将其添加到对象中并将该对象传递给调度。

const handleClick = () => dispatch({ type: "BUTTON_CLICKED", state: state });

代码沙盒:

【讨论】:

  • 谢谢。我可以从您放置的日志中看到 &lt;ChildDispatcher /&gt; 组件中的更新情况。这个状态是否也可以被推送到&lt;ChildConsumer /&gt; 组件?
  • 不知道我调用了 dispatch 函数错误。也感谢您的提示
  • 是的,您也可以在 ChildConsumer 中获取状态,因为它也在使用相同的 Context
【解决方案2】:

这个问题很少:

  1. ChildDispatch 状态仅对 ChildDispatch 可用,不会影响上层组件。要更改上下文值,您需要在该组件中提供调度并制作自定义挂钩(或将其作为道具传递)以在 ChildDispatch 中使用它。

  2. 调用调度时不要传递状态。 useReducer 将为您处理。只需发送操作即可。

这意味着您的数据流应该有一个单向方向。父组件控制共享状态/管理状态的方式,子组件使用它来呈现/执行操作。

【讨论】:

  • 谢谢。我想我考虑在父级中设置这个减速器函数,然后以某种方式通过上下文将调度作为道具传递,但是遇到了麻烦(并且也不确定这是否是反模式,或者我不应该的东西'不做)。我会进一步研究。
  • 我之所以考虑通过上下文传递它而不仅仅是作为道具是因为在我的实际项目中,子组件嵌套了一点,而不是直接嵌套在父组件下方。
猜你喜欢
  • 2020-06-05
  • 2020-07-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-06
  • 2021-10-18
  • 1970-01-01
  • 2018-06-07
  • 1970-01-01
相关资源
最近更新 更多