【问题标题】:React state not giving correct value on useEffect()反应状态没有在 useEffect() 上给出正确的值
【发布时间】:2022-01-24 09:44:57
【问题描述】:

我正在尝试使用 react 构建分解算法。 我想根据因式分解的结果将results 添加到LocalStorage。但是,LocalStorage 设置的是以前的结果而不是当前的结果。

我认为这是因为useEffect 在每个新的[number](=用户输入)上运行,而不是基于[results]。但是,我需要 useEffect 在新的用户输入提交上运行,因为那是必须触发分解的时候。

在分解完成后,我怎样才能使localStorage 设置正确的结果(如果可能,在finally 块上)?

const [results, setResults] = useState({
  default: [],
  detailed: [],
  isPrime: '',
});

const { number } = props

useEffect(() => {
  handleWorker(number);
  //accessing results here will give previous results
}, [number]);

const handleWorker = number => {
  try {
    const worker = new Worker(new URL('facto.js', import.meta.url));
    worker.postMessage({ number, algorithm });
    worker.onmessage = ({ data: { facto } }) => {
      setResults({ ...facto });
      //the worker 'streams live' results and updates them on setResults
    };
  } catch(error) {
    console.log(error.message)
  } finally {
    localStorage.setItem(number, results)
    //here, results is not current state but previous one
  }
};

请注意,其他一切正常

谢谢

【问题讨论】:

    标签: javascript reactjs react-hooks use-effect use-state


    【解决方案1】:

    您获得的是之前的值,因为localStorage.setItemsetResults 更新状态之前执行。你可以做一些重构来使它工作:

    const [results, setResults] = useState({
      default: [],
      detailed: [],
      isPrime: '',
    });
    
    const { number } = props;
    const workerRef = useRef(new Worker(new URL('facto.js', import.meta.url)));
    const worker = workerRef.current;
    
    useEffect(()=> {
        //-> create the listener just once
        worker.onmessage = ({ data: { facto } }) => {
          setResults({ ...facto }); 
        };
    }, []);
    
    useEffect(() => {
       //-> send message if number changed
       worker.postMessage({ number, algorithm });
    }, [number]);
    
    useEffect(() => {
       //-> update localStorage if results changed
       localStorage.setItem(number, results)
    }, [results]);
    

    【讨论】:

      【解决方案2】:

      这是你需要的(可能):

      const [results, setResults] = useState({ /* YOUR STATE */ });
      
      const { number } = props
      
      const handleWorker = useCallback((number) => {
        // DO WHATEVER YOU NEED TO DO HERE
      },[]); // IF YOU DEPEND ON ANY MUTABLE VARIABLES, ADD THEM TO THE DEPENDENCY ARRAY
      
      useEffect(() => {
        // DO WHATEVER YOU NEED TO DO HERE
        // INSTEAD OF localStorage.setItem(number, results)
        // DO localStorage.setItem(number, { ...facto })
      }, [number,handleWorker]);
      

      让我知道它是否有效。

      【讨论】:

      • try 块中设置 localStorage 效率不是很高,因为正如我所提到的,工作人员会流式传输实时结果。 localStorage 将多次设置相同的数字,但结果不同。最好只在最后设置 localStorage 的结果
      【解决方案3】:

      我认为您可以将结果状态作为 useEffect 的依赖项传递,因此每当结果的值发生变化时,useEffect 就会运行

      useEffect(() => { //code goes here}, [results]);
      

      假设结果还取决于函数handleWorker

      useEffect(() => { //code goes here},
          [results,handleWorker]);
      

      【讨论】:

      • 由于您将在 useEffect 函数中使用 handleworker,因此您必须将其添加为依赖项,因此每当结果更改时,useEffect 函数都会运行。 Handle Worker 在 useEffect 函数之外声明
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-26
      • 2021-04-29
      • 2021-07-20
      • 2019-01-04
      • 2023-02-16
      相关资源
      最近更新 更多