首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >React报错之无法在未挂载的组件上执行React状态更新

React报错之无法在未挂载的组件上执行React状态更新

作者头像
chuckQu
发布2022-08-19 16:35:03
发布2022-08-19 16:35:03
5.8K00
举报
文章被收录于专栏:前端F2E前端F2E
运行总次数:0

原文链接:https://bobbyhadz.com/blog/react-cant-perform-react-state-update-on-unmounted-component[1]

作者:Borislav Hadzhiev[2]

正文从这开始~

总览

为了解决"Warning: Can't perform a React state update on an unmounted component" ,可以在你的useEffect钩子中声明一个isMounted布尔值,用来跟踪组件是否被安装。一个组件的状态只有在该组件被挂载时才会被更新。

代码语言:javascript
代码运行次数:0
运行
复制
import {useState, useEffect} from 'react';

const App = () => {
  const [state, setState] = useState('');

  useEffect(() => {
    // 👇️ set isMounted to true
    let isMounted = true;

    async function fetchData() {
      const result = await Promise.resolve(['hello', 'world']);

      // 👇️ only update state if component is mounted
      if (isMounted) {
        setState(result);
      }
    }

    fetchData();

    return () => {
      // 👇️ when component unmounts, set isMounted to false
      isMounted = false;
    };
  }, []);

  return (
    <div>
      <h2>State: {JSON.stringify(state)}</h2>
    </div>
  );
};

export default App;

当我们试图更新一个未挂载的组件的状态时,会出现"无法在未挂载的组件上执行React状态更新"的警告。

isMounted

摆脱该警告的直截了当的方式是,在useEffect钩子中使用isMounted布尔值来跟踪组件是否被挂载。

useEffect中,我们初始化isMounted布尔值为true

我们的fetchData 函数执行一些异步的任务,最常见的是一个API请求,并根据响应来更新状态。

然而,需要注意的是,我们只有当isMounted变量被设置为true时,才会更新状态。

代码语言:javascript
代码运行次数:0
运行
复制
async function fetchData() {
  const result = await Promise.resolve(['hello', 'world']);

  // 👇️ only update state if component is mounted
  if (isMounted) {
    setState(result);
  }
}

这可以帮助我们避免警告,因为如果组件没有挂载,我们就不会更新状态。

当组件卸载时,从useEffect钩子返回的函数会被调用。

代码语言:javascript
代码运行次数:0
运行
复制
return () => {
  // 👇️ when component unmounts, set isMounted to false
  isMounted = false;
};

我们设置isMounted变量为false,表示该组件不再挂载。如果fetchData函数在组件卸载时被调用,if代码块不会执行是因为isMounted设置为false

代码语言:javascript
代码运行次数:0
运行
复制
async function fetchData() {
  const result = await Promise.resolve(['hello', 'world']);

  // 👇️ only update state if component is mounted
  if (isMounted) {
    setState(result);
  }
}

提取

如果经常这样做,可以将逻辑提取到可重用的钩子中。

代码语言:javascript
代码运行次数:0
运行
复制
import {useState, useEffect, useRef} from 'react';

// 👇️ extract logic into reusable hook
function useIsMounted() {
  const isMounted = useRef(false);

  useEffect(() => {
    isMounted.current = true;

    return () => {
      isMounted.current = false;
    };
  });

  return isMounted;
}

const App = () => {
  const [state, setState] = useState('');

  // 👇️ use hook
  const isMountedRef = useIsMounted();

  useEffect(() => {
    async function fetchData() {
      const result = await Promise.resolve(['hello', 'world']);

      // 👇️ only update state if component is mounted
      if (isMountedRef.current) {
        setState(result);
      }
    }

    fetchData();
  }, [isMountedRef]);

  return (
    <div>
      <h2>State: {JSON.stringify(state)}</h2>
    </div>
  );
};

export default App;

useRef()钩子可以传递一个初始值作为参数。该钩子返回一个可变的ref对象,其.current属性被初始化为传递的参数。

我们在useIsMounted钩子中跟踪组件是否被挂载,就像我们直接在组件的useEffect钩子中做的那样。

需要注意的是,在fetchData函数中,我们必须检查isMountedRef.current 的值,因为ref上的current属性是ref的实际值。

参考资料

[1]

https://bobbyhadz.com/blog/react-cant-perform-react-state-update-on-unmounted-component: https://bobbyhadz.com/blog/react-cant-perform-react-state-update-on-unmounted-component

[2]

Borislav Hadzhiev: https://bobbyhadz.com/about

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-08-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端F2E 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 总览
  • isMounted
  • 提取
    • 参考资料
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档