反应钩子.无法对卸载的组件执行 React 状态更新 [英] React-hooks. Can't perform a React state update on an unmounted component

查看:30
本文介绍了反应钩子.无法对卸载的组件执行 React 状态更新的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我收到此错误:

无法对卸载的组件执行 React 状态更新.这是无操作,但它表示您的应用程序中存在内存泄漏.修理,在 useEffect 清理中取消所有订阅和异步任务功能.

Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.

当开始获取数据并卸载组件时,但函数正在尝试更新卸载组件的状态.

when fetching of data is started and component was unmounted, but function is trying to update state of unmounted component.

解决这个问题的最佳方法是什么?

What is the best way to solve this?

CodePen 示例.

default function Test() {
    const [notSeenAmount, setNotSeenAmount] = useState(false)

    useEffect(() => {
        let timer = setInterval(updateNotSeenAmount, 2000) 

        return () => clearInterval(timer)
    }, [])

    async function updateNotSeenAmount() {
        let data // here i fetch data

        setNotSeenAmount(data) // here is problem. If component was unmounted, i get error.
    }

    async function anotherFunction() {
       updateNotSeenAmount() //it can trigger update too
    }

    return <button onClick={updateNotSeenAmount}>Push me</button> //update can be triggered manually
}

推荐答案

最简单的解决方案是使用局部变量来跟踪组件是否已安装.这是基于类的方法的常见模式.这是一个例子用钩子实现它:

The easiest solution is to use a local variable that keeps track of whether the component is mounted or not. This is a common pattern with the class based approach. Here is an example that implement it with hooks:

function Example() {
  const [text, setText] = React.useState("waiting...");

  React.useEffect(() => {
    let isCancelled = false;

    simulateSlowNetworkRequest().then(() => {
      if (!isCancelled) {
        setText("done!");
      }
    });

    return () => {
      isCancelled = true;
    };
  }, []);

  return <h2>{text}</h2>;
}

这是替代,带有useRef(见下文).请注意,对于依赖项列表,此解决方案将不起作用.第一次渲染后,ref 的值将保持为真.在这种情况下,第一种解决方案更合适.

Here is an alternative with useRef (see below). Note that with a list of dependencies this solution won't work. The value of the ref will stay true after the first render. In that case the first solution is more appropriate.

function Example() {
  const isCancelled = React.useRef(false);
  const [text, setText] = React.useState("waiting...");

  React.useEffect(() => {
    fetch();

    return () => {
      isCancelled.current = true;
    };
  }, []);

  function fetch() {
    simulateSlowNetworkRequest().then(() => {
      if (!isCancelled.current) {
        setText("done!");
      }
    });
  }

  return <h2>{text}</h2>;
}

您可以在此文章.这是 GitHub 上的 React 项目中展示此解决方案的一个问题.

You can find more information about this pattern inside this article. Here is an issue inside the React project on GitHub that showcase this solution.

这篇关于反应钩子.无法对卸载的组件执行 React 状态更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆