我创建了一个自定义钩子,将对象存储在useState钩子中,并允许更改属性而不会丢失其他条目。
const useObject = initialValue => {
const [state, setState] = useState(initialValue);
return [
state,
newState => {
setState({
...state,
...newState
});
}
];
};
此挂钩在我的组件中有效,但在将其分配给上下文时无效。
这是我所做的:
export const navigation = createContext();
https://codesandbox.io/s/keen-glitter-3nob7?file=/src/store.js:40-83
<navigation.Provider value={useObject()}>
https://codesandbox.io/s/keen-glitter-3nob7?file=/src/Layout.js:234-284
const [navigationState, setNavigationState] = useContext(navigation);
https://codesandbox.io/s/keen-glitter-3nob7?file=/src/App.js:476-616
结果:
上下文始终存储新条目并删除所有现有条目。
有人知道为什么吗?
这是“沙箱”链接。您可以通过单击过滤器按钮进行测试。我希望看到{search:true, icon: 'times'}
作为上下文值。谢谢!
https://codesandbox.io/s/keen-glitter-3nob7?file=/src/App.js
答案 0 :(得分:0)
这里要注意一件事。 App.js中的useEffect
仅运行一次,因此,使用setNavigationState设置的onClick函数将在其定义的点(即初始渲染)使用其闭包中的值。
由于这个原因,当您从上下文的Header.js中调用该函数时,该值连同localState都将重置为初始值。
解决方案1:
这里的一种解决方案是使用回调方法进行状态更新。为此,您需要稍微修改useObject的实现,以提供使用setState的回调值的功能
const useObject = initialValue => {
const [state, setState] = useState(initialValue);
return [
state,
newState => {
if(typeof newState === 'function') {
setState((prev) => ({ ...prev, ...newState(prev)}));
} else {
setState({
...state,
...newState
});
}
}
];
};
然后在onContextClick函数中使用它
const onContextClick = () => {
setState(prevState => {
setNavigationState(prev => ({ icon: ICON[prevState.isOpen ? 0 : 1] }));
return { isOpen: !prevState.isOpen };
});
};
解决方案2:
解决此问题的另一种更简单的方法是对useCallback
使用onContextClick并在每次关闭状态更新时使用useEffect更新导航状态
const onContextClick = React.useCallback(() => {
setNavigationState({ icon: ICON[state.isOpen ? 0 : 1] });
setState({ isOpen: !state.isOpen });
}, [state]);
useEffect(() => {
setNavigationState({
search: true,
icon: ICON[0],
onClick: onContextClick
});
}, [onContextClick]);