我在下面编写了一个自定义上下文提供程序,该应用程序将应用程序设置保存为Context
,并将其保存在localStorage
中(感谢Alex Krush的post)。
我添加了initialized
标志,以避免在组件安装后立即保存从localStorage
获取的值(useEffect
将在componentDidmount
的时间运行,并尝试将获取的值写入存储。)
import React,{ useCallback,useEffect,useReducer,useRef } from 'react';
const storageKey = 'name';
const defaultvalue = 'John Doe';
const initializer = (initialValue) => localStorage.getItem(storageKey) || initialValue;
const reducer = (value,newValue) => newValue;
const CachedContext = React.createContext();
const CachedContextProvider = (props) => {
const [value,setvalue] = useReducer(reducer,defaultvalue,initializer);
const initialized = useRef(false);
// save the updated value as a side-effect
useEffect(() => {
if (initialized.current) {
localStorage.setItem(storageKey,value);
} else {
initialized.current = true; // skip saving for the first time
}
},[value]);
return (
<CachedContext.Provider value={[value,setvalue]}>
{props.children}
</CachedContext.Provider>
);
};
用法:
const App = (props) => {
return <CachedContextProvider><Name name='Jane Doe' /></CachedContextProvider>;
}
const Name = (props) => {
const [name,setName] = useContext(CachedContext);
useEffect(() => {
setName(props.name);
},[props.name]);
}
然后,我想让我的自定义上下文检测到另一个窗口对目标存储所做的更改。我将handleStorageEvent
添加到CachedContextProvider
来监听存储事件:
// re-initialize when the storage has been modified by another window
const handleStorageEvent = useCallback((e) => {
if (e.key === storageKey) {
initialized.current = false; // <-- is it safe???
setvalue(initializer(defaultvalue));
}
},[]);
useEffect(() => {
if (typeof window !== 'undefined') {
window.addEventListener('storage',handleStorageEvent);
return () => {
window.removeEventListener('storage',handleStorageEvent);
};
}
},[]);
我担心的是是否可以安全地将initialized
重置为false
以避免写回获取的值。我担心多进程设置中的以下情况:
- 窗口1运行
setvalue('Harry Potter')
- 窗口2运行
setvalue('Harry Potter')
- 窗口2运行
localStorage.setItem
以响应value
上的更新
窗口1中的 -
handleStorageEvent
检测到存储更改,并将其initialized
和value
初始化为false
和'Harry Potter'
- 窗口1尝试运行
localStorage.setItem
,但是它没有任何作用,因为窗口2已经将value
设置为'Harry Potter'
,并且React可能会判断没有变化。结果,initialized
将保留为false
- 窗口1运行
setvalue('Ron Weasley')
。它会更新value
,但不会保存,因为initialized === false
。有机会失去应用程序设置的值
我认为这与React的useEffect
和DOM事件处理程序之间的执行顺序有关。有人知道怎么做对吗?