React usePersistedState钩子

返回一个在localStorage中持久化的状态值和一个更新它的函数。

  • 使用useState()钩子将value初始化为defaultValue
  • 使用useRef()钩子创建一个引用,用于保存Window.localStorage中值的name
  • 使用3个useEffect()钩子实现初始化、value变化和name变化。
  • 当组件首次挂载时,使用Storage.getItem()更新value,如果有存储的值,则使用Storage.setItem()持久化当前值。
  • value更新时,使用Storage.setItem()存储新值。
  • name更新时,使用Storage.setItem()创建新的键,更新nameRef,并使用Storage.removeItem()Window.localStorage中删除前一个键。

[!NOTE]

该钩子适用于原始值(即非对象),并且不考虑由于其他代码而导致的Window.localStorage的更改。这两个问题都可以很容易地处理(例如JSON序列化和处理'storage'事件)。

const usePersistedState = (name, defaultValue) => {
  const [value, setValue] = React.useState(defaultValue);
  const nameRef = React.useRef(name);

  React.useEffect(() => {
    try {
      const storedValue = localStorage.getItem(name);
      if (storedValue !== null) setValue(storedValue);
      else localStorage.setItem(name, defaultValue);
    } catch {
      setValue(defaultValue);
    }
  }, []);

  React.useEffect(() => {
    try {
      localStorage.setItem(nameRef.current, value);
    } catch {}
  }, [value]);

  React.useEffect(() => {
    const lastName = nameRef.current;
    if (name !== lastName) {
      try {
        localStorage.setItem(name, value);
        nameRef.current = name;
        localStorage.removeItem(lastName);
      } catch {}
    }
  }, [name]);

  return [value, setValue];
};

const MyComponent = ({ name }) => {
  const [val, setVal] = usePersistedState(name, 10);
  return (
    <input
      value={val}
      onChange={e => {
        setVal(e.target.value);
      }}
    />
  );
};

const MyApp = () => {
  const [name, setName] = React.useState('我的值');
  return (
    <>
      <MyComponent name={name} />
      <input
        value={name}
        onChange={e => {
          setName(e.target.value);
        }}
      />
    </>
  );
};

ReactDOM.createRoot(document.getElementById('root')).render(
  <MyApp />
);