简体   繁体   English

使用 useReducer 从一个子组件分派动作并更新另一个子组件中的状态

[英]Using useReducer to dispatch action from one child component and update state in another child component

Here is a CodeSandbox that has the example code below, and the linter highlights some of the issues: https://codesandbox.io/s/react-repl-bw2h1这是一个 CodeSandbox,其中包含下面的示例代码,并且 linter 突出了一些问题: https ://codesandbox.io/s/react-repl-bw​​2h1

Below is a basic example of what I'm trying to do.下面是我正在尝试做的一个基本示例。 In a container component, I have a context AppContext that is providing state to child components, <ChildConsumer /> and <ChildDispatcher /> .在容器组件中,我有一个上下文AppContext ,它为子组件<ChildConsumer /><ChildDispatcher />提供状态。

The <ChildConsumer /> component is receiving this state using useContext , and this seems to be working as expected. <ChildConsumer />组件正在使用useContext接收此状态,这似乎按预期工作。

Inside <ChildDispatcher /> , I'm trying to dispatch an action when a button is clicked.<ChildDispatcher /> ,我试图在单击按钮时分派一个动作。 To do this, I've created a reducer reducer that handles an action.为此,我创建了一个处理操作的 reducer reducer I've also set up useReducer here that takes in reducer and the initial store state.我还在这里设置了 useReducer,它接收reducer和初始store状态。

When I click the button, nothing happens.当我单击按钮时,没有任何反应。 What I'm expecting to happen is that the dispatch receives both the state pulled off of useReducer as well as an action object, and passes these to the reducer.我期望发生的是dispatch接收从useReduceraction对象拉出的state ,并将它们传递给 reducer。 The reducer should see that the action of type BUTTON_CLICKED was received, and should return a new state containing the old state as well as an additional 'goodbye' item.减速器应该看到收到了BUTTON_CLICKED类型的动作,并且应该返回一个包含旧状态的新状态以及一个额外的'goodbye'项目。 Then, the child component <ChildConsumer /> should rerender with this new state.然后,子组件<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);

I have made a small amendment in you code.我对你的代码做了一个小的修改。

you have to pass the dispatch like below.你必须通过如下所示的调度。 Dispatch expects an argument of type object. Dispatch 需要一个 object 类型的参数。

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

And then this state could be accessed like this.然后可以像这样访问这个状态。

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>;
};

By default react will pass the state to the dispatcher.默认情况下,react 会将状态传递给调度程序。 but if you want to pass some data the you can add it in the object and pass that object to dispatch.但是如果你想传递一些数据,你可以将它添加到对象中并将该对象传递给调度。

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

CodeSandBox:代码沙盒:

编辑反应回复

Few problems with this:这有几个问题:

  1. The ChildDispatch state is only available to ChildDispatch and will not affect upper level components. ChildDispatch 状态只对 ChildDispatch 可用,不会影响上层组件。 To change the context value, you need to provide a dispatch in that component and make a custom hook (or pass it as props) to use it in the ChildDispatch.要更改上下文值,您需要在该组件中提供一个调度并制作一个自定义钩子(或将其作为道具传递)以在 ChildDispatch 中使用它。

  2. Don't pass state when calling your dispatch.调用您的调度时不要传递状态。 useReducer will handle that for you. useReducer 将为您处理。 Just send the action.只需发送操作即可。

This is what it means that there should be a one way direction for your data flow.这就是数据流应该有一个单向方向的意思。 Parent components control the shared state / way to manage state, and child components use that to render / perform actions.父组件控制共享状态/管理状态的方式,子组件使用它来呈现/执行操作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM