React hooks:在子组件中调用分派时父组件不更新
React hooks: Parent component not updating when dispatch is called in a child component
我一直在按照指南使用 useContext 将 reducer 传递给子组件,但是当从子组件调度时,它似乎没有重新渲染父组件。
状态本身似乎在从子组件调度时正确更新(由 console.logging state.count 完成),但父组件不反映状态的变化。
我尝试将调度函数作为 prop 传递给 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>
)
}
那是因为你是 re-creating 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
的每个渲染器上获得 re-declared。
这是一个 运行 示例:
// 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"/>
我一直在按照指南使用 useContext 将 reducer 传递给子组件,但是当从子组件调度时,它似乎没有重新渲染父组件。
状态本身似乎在从子组件调度时正确更新(由 console.logging state.count 完成),但父组件不反映状态的变化。
我尝试将调度函数作为 prop 传递给 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>
)
}
那是因为你是 re-creating 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
的每个渲染器上获得 re-declared。
这是一个 运行 示例:
// 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"/>