React的useEffect和DOM事件处理程序之间的执行顺序

问题描述 投票:0回答:1

[我在下面编写了一个自定义上下文提供程序,该应用程序将应用程序设置保存为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. 窗口1运行setValue('Harry Potter')
  2. 窗口2运行setValue('Harry Potter')
  3. 窗口2运行localStorage.setItem以响应对value的更新
  4. handleStorageEvent检测到存储的更改,并将其initializedvalue重新初始化为false'Harry Potter'
  5. Window 1尝试运行localStorage.setItem,但是它没有任何作用,因为Window 2已经将value设置为'Harry Potter',并且React可能会判断没有更改。结果,initialized将保持为false
  6. 窗口1运行setValue('Ron Weasley')。它更新value,但
  7. 不保存它,因为initialized === false。有机会丢失应用程序设置的值
我认为这与React的useEffect和DOM事件处理程序之间的执行顺序有关。有人知道该怎么做吗?
javascript reactjs local-storage web-storage
1个回答
0
投票
我可能会添加某种测试,以查看在每种可能的情况下会发生什么。

但是,这是我的理论:在第5步中,窗口1将不会尝试运行localStorage.setItem(如您所说),因为初始化设置只是设置为false。相反,它将设置为true。因此,第6步应该可以按预期工作,这应该不是问题。

© www.soinside.com 2019 - 2024. All rights reserved.