reactjs - React:自定义钩子不适用于上下文
问题描述
我创建了一个自定义挂钩来将对象存储在 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
- 我创建了一个 useObject 变量并将其作为值分配给我的 Context Provider
<navigation.Provider value={useObject()}>
https://codesandbox.io/s/keen-glitter-3nob7?file=/src/Layout.js:234-284
- 我通过 useContext 加载上下文并更改其值
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
解决方案
这里有一件重要的事情需要注意。useEffect
在 App.js 中运行一次,因此使用 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]);
推荐阅读
- java - 为什么 Mockito.when(...).thenThrow(...) 直接抛出错误
- node.js - 如何在 Nodejs 中将流转换为可下载的文件?
- python - 读取图像并在opencv中处理它们
- javascript - 从孩子到孩子的访问方法
- python - 从 PDF(目录)中提取文本忽略页面和索引编号
- oracle - 我有一个保存日期的 varchar2 字段。如何检查格式?
- azure - Azure datafactory v2 -dataset copy activty -zipdeflate
- regex - 替换所有捕获的组,但首先在 sed
- c# - 使用 SOCKS 5 C# 的 FTP
- javascript - 量角器 - 如何跳转到网格中的下一行并返回找到的值