React hooks:在子组件中调用调度时父组件不更新

Ste*_*sen 5 javascript reactjs react-hooks

我一直在遵循使用 useContext 将减速器传递给子组件的指南,但是当从子组件分派时,它似乎没有重新渲染父组件。

从子组件分派时,状态本身似乎正确更新(如通过 console.logging state.count 完成的),但父组件不反映状态的更改。

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

应用程序.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;
Run Code Online (Sandbox Code Playgroud)

减速器.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);
Run Code Online (Sandbox Code Playgroud)

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>
    )
}
Run Code Online (Sandbox Code Playgroud)

Sag*_*b.g 4

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

<StateContext.Provider value={useReducer(reducer, initialState)}>
Run Code Online (Sandbox Code Playgroud)

相反,只需传递实际的减速器即可dispatch

<StateProvider initialState={initialState} reducer={{dispatch}}> 
Run Code Online (Sandbox Code Playgroud)

然后使用它:

const StateProvider = ({reducer, initialState, children}) => (
    <StateContext.Provider value={reducer}>
        {children}
    </StateContext.Provider>
);
Run Code Online (Sandbox Code Playgroud)

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

这是一个运行示例:

<StateContext.Provider value={useReducer(reducer, initialState)}>
Run Code Online (Sandbox Code Playgroud)
<StateProvider initialState={initialState} reducer={{dispatch}}> 
Run Code Online (Sandbox Code Playgroud)