【问题标题】:React hooks: Parent component not updating when dispatch is called in a child componentReact hooks:在子组件中调用调度时父组件不更新
【发布时间】:2019-07-06 10:07:01
【问题描述】:

我一直在按照指南使用 useContext 将 reducer 传递给子组件,但是从子组件调度时,它似乎没有重新渲染父组件。

从子组件调度时,状态本身似乎正在正确更新(由 console.logging state.count 完成),但父组件不反映状态的变化。

我尝试将调度函数作为道具传递给 Child,这确实更新了 App.js,但我认为我的方法更简洁,我可能会做错事。我还将{state.count} 放在 Child.js 中,它确实得到了正确更新,但对于这种情况,我需要在父组件中使用它。代码如下:

App.js

import React, { useReducer } from 'react';
import { StateProvider } from './reducer';
import Child from './Child'

function App() {
    const reducer = (state, action) => {
        switch (action.type) {
            case 'add':
                console.log(state.count+1)
                return {...state, count: state.count + 1}
            default:
                throw new Error();
        }
    }

    const initialState = {count: 1};
    const [state, dispatch] = useReducer(reducer, initialState)

    return (
        <StateProvider initialState={initialState} reducer={reducer}>
            <div className="App">
                {state.count}
                <Child></Child>
            </div>
        </StateProvider>
  );
}

export default App;

reducer.js

import React, {createContext, useContext, useReducer} from 'react';

export const StateContext = createContext(null);

export const StateProvider = ({reducer, initialState, children}) => (
    <StateContext.Provider value={useReducer(reducer, initialState)}>
        {children}
    </StateContext.Provider>
);

export const useStateValue = () => useContext(StateContext);

Child.js

import React from 'react';
import { useStateValue } from './reducer';

export default function Child(props) {
    const [state, dispatch] = useStateValue();

    return (
        <button onClick={() => dispatch({type: 'add'})}>Increment</button>
    )
}

【问题讨论】:

    标签: javascript reactjs react-hooks


    【解决方案1】:

    那是因为你在StateProvider 中重新创建了一个reducer:

    <StateContext.Provider value={useReducer(reducer, initialState)}>
    

    相反,只需将实际减速器的dispatch 向下传递:

    <StateProvider initialState={initialState} reducer={{dispatch}}> 
    

    然后使用它:

    const StateProvider = ({reducer, initialState, children}) => (
        <StateContext.Provider value={reducer}>
            {children}
        </StateContext.Provider>
    );
    

    顺便说一句,我认为您可以在组件外部声明 reducer 逻辑函数,这样它就不会在每次呈现 App 时无缘无故地重新声明。

    这是一个运行示例:

    // mimic imports
    const {createContext, useContext, useReducer} = React;
    
    const StateContext = createContext(null);
    
    const StateProvider = ({reducer, initialState, children}) => (
        <StateContext.Provider value={reducer}>
            {children}
        </StateContext.Provider>
    );
    
    const useStateValue = () => useContext(StateContext);
    
    function Child(props) {
      const {dispatch} = useStateValue(StateContext);
    
      return (
          <button onClick={() => dispatch({type: 'add'})}>Increment</button>
      )
    }
    
    const reducer = (state, action) => {
      switch (action.type) {
          case 'add':
              console.log(state.count+1)
              return {...state, count: state.count + 1}
          default:
              throw new Error();
      }
    }
    
    function App() {
        const initialState = {count: 1};
        const [state, dispatch] = useReducer(reducer, initialState)
        return (
            <StateProvider initialState={initialState} reducer={{dispatch}}>
                <div className="App">
                    {state.count}
                    <Child></Child>
                </div>
            </StateProvider>
      );
    }
    
    const rootElement = document.getElementById("root");
    ReactDOM.render(<App />, rootElement);
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.1/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.1/umd/react-dom.production.min.js"></script>
    <div id="root"/>

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-01-06
      • 2021-07-24
      • 2018-10-09
      • 2020-08-08
      • 2020-02-05
      • 2015-11-30
      • 2021-05-08
      • 1970-01-01
      相关资源
      最近更新 更多