反应挂钩:在子组件中调用dispatch时,父组件未更新

时间:2019-07-06 10:07:01

标签: javascript reactjs react-hooks

我一直在遵循使用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>
    )
}

1 个答案:

答案 0 :(得分:2)

那是因为您正在reducer中重新创建StateProvider

<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"/>