小编典典

在React useEffect钩子中引用过时的状态

reactjs

我想将状态保存到localStorage卸载组件时。这曾经在中工作componentWillUnmount

我尝试对useEffect钩子执行相同的操作,但是在返回函数中似乎状态不正确useEffect

这是为什么?如何不使用课程就可以保存状态?

这是一个虚拟的例子。当您按关闭时,结果始终为0。

import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";

function Example() {
  const [tab, setTab] = useState(0);
  return (
    <div>
      {tab === 0 && <Content onClose={() => setTab(1)} />}
      {tab === 1 && <div>Why is count in console always 0 ?</div>}
    </div>
  );
}

function Content(props) {
  const [count, setCount] = useState(0);

  useEffect(() => {
    // TODO: Load state from localStorage on mount

    return () => {
      console.log("count:", count);
    };
  }, []);

  return (
    <div>
      <p>Day: {count}</p>
      <button onClick={() => setCount(count - 1)}>-1</button>
      <button onClick={() => setCount(count + 1)}>+1</button>
      <button onClick={() => props.onClose()}>close</button>
    </div>
  );
}

ReactDOM.render(<Example />, document.querySelector("#app"));

CodeSandbox


阅读 272

收藏
2020-07-22

共1个答案

小编典典

我尝试对useEffect挂钩执行相同的操作,但是在useEffect的返回函数中状态似乎不正确。

其原因是由于关闭。闭包是函数在其范围内对变量的引用。useEffect挂载组件时,您的回调仅运行一次,因此返回回调引用的初始计数值为0。

这里给出的答案就是我的建议。我建议@Jed
Richard将答案传递[count]useEffect,它的作用是localStorage仅在计数更改时才写入。这比在每次更新中完全不传递任何内容的方法要好。除非您非常频繁地更改计数(每隔几毫秒),否则就不会出现性能问题,并且localStorage每当count发生更改时都可以写入。

useEffect(() => { ... }, [count]);

如果您坚持只写localStorage卸载文件,则可以使用一个丑陋的hack /解决方案-
参考。基本上,您将创建一个在组件的整个生命周期中都存在的变量,您可以从组件中的任何位置进行引用。但是,您必须手动将状态与该值同步,这非常麻烦。引用不会给您上述关闭问题,因为引用是一个具有current字段的对象,多次调用useRef将返回相同的对象。只要您更改该.current值,您useEffect就可以始终(仅)读取最新的值。

CodeSandbox链接

const {useState, useEffect, useRef} = React;



function Example() {

  const [tab, setTab] = useState(0);

  return (

    <div>

      {tab === 0 && <Content onClose={() => setTab(1)} />}

      {tab === 1 && <div>Count in console is not always 0</div>}

    </div>

  );

}



function Content(props) {

  const value = useRef(0);

  const [count, setCount] = useState(value.current);



  useEffect(() => {

    return () => {

      console.log('count:', value.current);

    };

  }, []);



  return (

    <div>

      <p>Day: {count}</p>

      <button

        onClick={() => {

          value.current -= 1;

          setCount(value.current);

        }}

      >

        -1

      </button>

      <button

        onClick={() => {

          value.current += 1;

          setCount(value.current);

        }}

      >

        +1

      </button>

      <button onClick={() => props.onClose()}>close</button>

    </div>

  );

}



ReactDOM.render(<Example />, document.querySelector('#app'));


<script src="https://unpkg.com/[email protected]/umd/react.development.js"></script>

<script src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script>



<div id="app"></div>
2020-07-22