正文从这开始~

总览

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

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时,才会更新状态。

async function fetchData() {
const result = await Promise.resolve(['hello', 'world']); // ️ only update state if component is mounted
if (isMounted) {
setState(result);
}
}

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

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

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

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

async function fetchData() {
const result = await Promise.resolve(['hello', 'world']); // ️ only update state if component is mounted
if (isMounted) {
setState(result);
}
}

提取

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

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的实际值。

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

  1. VM中装Linux换ISO文件报错"该光盘无法被挂载"

    一.发现问题 利用VM安装Red Hat Linux的时候,第一个iso安装完毕,准备换第二个iso,报错“该光盘无法被挂载”. 二.解决办法 上面的菜单栏中“虚拟机”—>“设置”—>“硬 ...

  2. Oracle添加记录的时候报错:违反完整性约束,未找到父项关键字

    今天需要向一个没有接触过的一个Oracle数据库中添加一条记录,执行报错: 分析: 报错的根本原因:未找到父项关键字的原因是因为你在保存对象的时候缺失关联对象. 问题的解决思路:先保存关联对象后再保存 ...

  3. react 报错的堆栈处理

    react报错 Warning: You cannot PUSH the same path using hash history 在Link上使用replace 原文地址https://reactt ...

  4. [转]ORACLE 11G 导出报错(EXP-00003)未找到段 (0,0) 的存储定义

    http://blog.csdn.net/qq_19524879/article/details/51313205 ORACLE 11G 导出报错(EXP-00003)未找到段 (0,0) 的存储定义 ...

  5. 解决Oracle+Mybatis批量插入报错:SQL 命令未正确结束

    Mybatis批量插入需要foreach元素.foreach元素有以下主要属性: (1)item:集合中每一个元素进行迭代时的别名. (2)index:指定一个名字,用于表示在迭代过程中,每次迭代到的 ...

  6. 报错:该字符串未被识别为有效的DateTime

    报错:该字符串未被识别为有效的DateTime □ 背景 前端的搜索条件中包含关于时间的字符串,由jquery ui的datepicker产生时间字符串. 服务端对时间做了一次转换:DateTime. ...

  7. 小程序报错:出现脚本错误或者未正确调用 Page()的解决办法

    场景是两个人共同开发小程序,我使用的是pc端,另一个同事是用的mac端,我这边能够正常运行项目,代码提交到git,同事check下来发现运行报错: 出现脚本错误或者未正确调用 Page(); 如图 一 ...

  8. React报错之Cannot find namespace context

    正文从这开始~ 总览 在React中,为了解决"Cannot find namespace context"错误,在你使用JSX的文件中使用.tsx扩展名,在你的tsconfig. ...

  9. angularjs 遇见$scope,xxx=function()报错为该函数未定义

    本包子今天遇见一个问题,就是明明写了$scope,xx=function()但是报错了,报错显示是该函数未定义,我就很着急的先将函数写成一个全局函数,就没问题,等下午有空的时候寻思了一下,为什么全局就 ...

随机推荐

  1. Flask表单验证

    学习内容:①判断请求方式(request.method) from flask import Flask,render_template,request app = Flask(__name__) @ ...

  2. Fail2ban 配置详解 配置说明

    fail2ban的配置主要由基础配置(fail2ban.conf)和监禁配置(jail.conf)两部分组成. fail2ban的配置采用标签块"[块名]"和键值"key ...

  3. 2021.04.03【NOIP提高B组】模拟 总结

    T1 题目大意:求最小的 \(n\in[0,lim]\) 使得区间 \([L,R]\) 在线段树建树 \(build(0,n)\) 的区间内 考场时想到了正解,结果推式子退错了... 其实就是从下往上 ...

  4. 5G的发布加快了智慧城市/三维物联网等行业的发展

    最近很多人发现自己的5G手机突然没了5G信号,难道是美国搞的鬼? 不不不,这其实是因为5G的NSA基站被撤站了,官方已经做了部署,要大力推进SA网络建设.所以之前支持NSA模式的5G手机,现在都成了4 ...

  5. 论文解读(USIB)《Towards Explanation for Unsupervised Graph-Level Representation Learning》

    论文信息 论文标题:Towards Explanation for Unsupervised Graph-Level Representation Learning论文作者:Qinghua Zheng ...

  6. 粗谈对ajax的理解

    ajax:Asynchronous JavaScript and XML异步JavaScript和XML技术Asynchronous:JavaScript:XMLHttpRequestXML:实现数据 ...

  7. Windows下MySQL的安装和删除

    Windows下MySQL的安装和删除 安装Mysql 1 下载mysql 地址 2 安装教程 2.1配置环境变量 变量名:MYSQL_HOME 变量值:D:\software\programming ...

  8. SpringBoot之缓存

    一.准备工作 首先整合使用Spring整合MyBatis. 可参阅:SpringBoot整合MyBatis SpringBoot整合MyBatis完后后,我们需要在pom.xml中添加缓存相关的依赖. ...

  9. 【黑马pink老师的H5/CSS课程】(一)基本介绍

    视频P4~P6 黑马程序员pink老师前端入门教程,零基础必看的h5(html5)+css3+移动 1.网页 1.1 什么是网页 网站是网页的集合,网页是构成网站的基本元素,常用html格式文件 1. ...

  10. 工具箱之 IKVM.NET 项目新进展

    在各种群里经常讨论的一个事情是.NET 如何调用 Java 的实现,最常见的场景之一就是在加解密方面Java提供的密钥,C#无法解密, C#中byte范围是[0,255],而Java中的byte范围是 ...