使用useReducer调度一个子组件的操作并更新另一个子组件的状态

时间:2020-03-07 17:20:30

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

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

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

<ChildConsumer />组件正在使用useContext接收此状态,并且似乎可以正常工作。

<ChildDispatcher />内部,我试图在单击按钮时调度一个动作。为此,我创建了一个处理操作的化简器reducer。我还在这里设置了useReducer,它具有reducer和初始store状态。

当我单击按钮时,什么也没有发生。我期望发生的事情是,dispatch接收到从state提取的useReducer以及一个action对象,并将它们传递给减速器。精简器应看到已收到类型为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);

2 个答案:

答案 0 :(得分:1)

我在您的代码中做了一个小修改。

您必须通过如下所示的调度。调度需要一个类型为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 });

CodeSandBox:

Edit react repl

答案 1 :(得分:1)

与此相关的几个问题:

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

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

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