我不会向您介绍更广泛的背景,因为它非常简单。使用 React hooks,这里的第一个调度会自动触发并且工作得很好,但第二个则不然。 Context
是从另一个文件导入的,所以我认为这是一个(小写)上下文问题,但我不知道如何修复它?
const Component = props => {
const [, dispatch] = useContext(Context);
useEffect(() => {
document.title = state.title;
// eslint-disable-next-line react-hooks/exhaustive-deps
});
// this works
dispatch({ type: "UPDATE_TITLE", payload: "Not Click!" });
function onAddClick() {
// this doesn't work
dispatch({ type: "UPDATE_TITLE", payload: "CLICKED!" });
}
return (
<div>
<AddButton onClick={onAddClick} />
</div>
);
};
这是父级。
const Reducer = (state, action) => {
switch (action.type) {
case "UPDATE_TITLE":
state["title"] = action.payload;
return state;
default:
return state;
}
};
const initialState = {
title: "My Title"
};
export const Context = createContext(initialState);
const App = () => {
const [state, dispatch] = useReducer(Reducer, initialState);
return (
<Context.Provider value={[state, dispatch]}>
<Component />
</Context.Provider>
);
};
export default App;
在这两种情况下,控制台日志都会在正确的 reducer 情况下触发,但只有标记为“此有效”的那个才会真正正确更新状态,另一种则默默地失败。
已修复:https://codesandbox.io/s/cranky-wescoff-9epf9?file=/src/App.js
最佳答案
我不知道你想通过将 dispatch
放置在 control
env 之外来实现什么目的(例如 event
或 useEffect
):-
// this works
dispatch({ type: "UPDATE_TITLE", payload: "Not Click!" });
// but it will run in infinite loop tho (no changes can be made then)
所以修复应该是:-
- 在
Reducer
中,确保不要完全改变
您的状态
:-
const Reducer = (state, action) => {
switch (action.type) {
case "UPDATE_TITLE":
// Don't do this
// let newState = state;
// newState["page"]["title"] = action.payload;
// console.log("updating", newState, newState.page.title);
// return newState;
// Do this instead
return {
...state,
page: {
...state.page,
title: action.payload
}
};
default:
return state;
}
};
- 将
not Click!
的dispatch
放置在event
或function
中,或者在这种情况下更好,useEffect
因为您想在渲染的组件
中应用它一次
。
const Demo = props => {
const [state, dispatch] = useContext(Context);
useEffect(() => {
document.title = state.title;
// eslint-disable-next-line react-hooks/exhaustive-deps
// this works (should be here)
dispatch({ type: "UPDATE_TITLE", payload: "Not Click!" });
}, []); // run it once when render
// this works but, (should not be here tho - cause it will run non-stop)
// dispatch({ type: "UPDATE_TITLE", payload: "Not Click!" });
function onAddClick() {
// this will work now
dispatch({ type: "UPDATE_TITLE", payload: "CLICKED!" });
}
return (
<div>
<button onClick={onAddClick}>Click Me!</button>
<p>State now: {state.title}</p>
</div>
);
};
你可以尝试引用这个sandbox并看看它是如何工作的。
编辑和更新sandbox
关于reactjs - useReducer 和 useContext Dispatch 在 onClick 函数中不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64938820/