位置: IT常识 - 正文

React18的useEffect会执行两次

编辑:rootadmin
React18的useEffect会执行两次 React18的useEffect会执行两次一、执行两次的useEffect。二、React18 useEffect 新特性如何应对1.首先先了解一下 React 中 useEffect 执行的时机2.怎么样才能让 Effect 执行一次?。1)清理事件监听2-1)重置页面数据,清理属性状态2-2)重置页面数据,还原元素状态2-3)重置页面数据,弹窗类。3-1)异步请求页面数据处理,处理异步数据渲染3-2)异步请求页面数据处理,处理接口请求4)无须清理类5)日志 log 上报类一、执行两次的useEffect。

推荐整理分享React18的useEffect会执行两次,希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:,内容如对您有帮助,希望把文章链接给更多的朋友!

前段时间在本地启了一个 React Demo 项目,在编码的过程中遇到一个很奇怪的“Bug”。 其中简化版的代码如下所示。

// 入口文件import { StrictMode } from 'react';import * as ReactDOMClient from 'react-dom/client';import App from './App';const root = ReactDOMClient.createRoot(document.getElementById('root'));root.render( <StrictMode> <App /> </StrictMode>);// 组件代码import React, { useEffect } from 'react';const App = () => { useEffect(() => { console.log('组件挂载完成!'); }, []); return <>Hello world!</>;};

我是万万没想到,就这样几行简单的代码竟然会触发一个“Bug”。 此“Bug”的表现为:在 Chrome 控制台里发现 “Hello world!” 被打印了 “两次”。 刷新之后依然如此,当时就给我整懵了,第一感觉就是,这怎么可能? 很是纠结一番之后依然没想明白,于是试着去网上搜了一下,发现竟然有人同样遇到过这个问题。

通过网上指引,同时去官网查了一下,终于得出答案。

这不是 Bug,这是 React18 新加的特性。二、React18 useEffect 新特性1.这是 React18 才新增的特性。2.仅在开发模式("development")下,且使用了严格模式("Strict Mode")下会触发。 生产环境("production")模式下和原来一样,仅执行一次。3.之所以执行两次,是为了模拟立即卸载组件和重新挂载组件。 为了帮助开发者提前发现重复挂载造成的 Bug 的代码。 同时,也是为了以后 React的新功能做铺垫。 未来会给 React 增加一个特性,允许 React 在保留状态的同时,能够做到仅仅对UI部分的添加和删除。 让开发者能够提前习惯和适应,做到组件的卸载和重新挂载之后, 重复执行 useEffect的时候不会影响应用正常运行。如何应对

看过文档以及了解他们这么做的本意之后,我也能够理解他们会这样做了。 只是,对于这种半强迫式操作多少有些不喜欢,感觉是在代码中”被强迫打一针疫苗?”。

当然,人家就是这么干了,作为 React 的普通使用者,能做的就是 适应它 ,并按照它的规范来做。

1.首先先了解一下 React 中 useEffect 执行的时机Every time your component renders, React will update the screen and then run thecode inside useEffect.

每次组件渲染时,React 都会更新页面 UI,然后运行 useEffect 中的代码。

Effects run at the end of the rendering process after the screen updates

Effect 在屏幕更新之后的 rendering 进程结束的时候执行。

从上面可以得出结论,React 中的 useEffect 执行时机是在组件渲染之后(类似于 window(component).onload ?)。 因此,对于某些“副作用”的渲染,比如异步接口请求,事件绑定等操作我们通常都放在 useEffect 中执行。

当然,useEffect 除了在组件渲染的时候执行外,在组件卸载的时候也有相关执行操作。 在组件卸载的时候会执行 useEffect 方法的return语句。

useEffect(() => { window.a = 100; return (window.a = 0);}, []);

如上代码段,当组件渲染的时候会执行window.a = 100,当组件卸载的时候会执行window.a = 0。

知道了 useEffect 的执行时机,也就能明白为什么 React18 中 useEffect 会执行两次了。

因为, React18 在开发环境中除了必要的挂载之外,还 "额外"模拟执行了一次组件的卸载和挂载。React18的useEffect会执行两次

既然知道了原因,那么,接下来就是想办法解决了。

2.怎么样才能让 Effect 执行一次?。

对于这个问题,官方文档上面有一句原话:The right question isn’t “how to run an Effect once,” but “how to fix my Effect so that it works after remounting”.翻译一下,就是说:正确的问题不是“怎么样让 Effect 执行一次”,而是“怎样修复我的 Effect,让它在(重复)挂载之后正常工作” 也可以理解,毕竟在 React 的未来版本中做离屏渲染的时候 useEffect 肯定会多次执行的。 而且,即使是当前版本,在做页面的前进后退也会面临触发多次 useEffect。

所以,解决办法其实就是解决 重复挂载卸载之后 应用正常工作了。 ###3.具体的解决方法 我们知道 useEffect 支持返回一个函数,在组件卸载的时候就会执行该函数。 因此,通常正确解法就是 实现清理函数,并将其在 useEffect 中返回。 当然,不同的 Effect 需要有不同的清理方式。

在常用 Effect 分类下,大致有如下几类清理。

1)清理事件监听useEffect(() => { function handleScroll(e) { console.log(e.clientX, e.clientY); } window.addEventListener('scroll', handleScroll); return () => window.removeEventListener('scroll', handleScroll);}, []);

对于事件监听类函数,在返回函数内部“取消掉事件监听”即可。

2-1)重置页面数据,清理属性状态useEffect(() => { const node = ref.current; node.style.opacity = 1; // Trigger the animation return () => { node.style.opacity = 0; // Reset to the initial value };}, []);

对于一些页面属性的变更,在返回函数内部将其变更的属性进行还原。

2-2)重置页面数据,还原元素状态import { useEffect, useRef } from 'react';function VideoPlayer({ src, isPlaying }) { const ref = useRef(null); useEffect(() => { if (isPlaying) { ref.current.play(); } else { ref.current.pause(); } }); return <video ref={ref} src={src} loop playsInline />;}

涉及到元素状态的,比如播放器之类,需要对(元素)播放器的状态进行重置。

2-3)重置页面数据,弹窗类。useEffect(() => { const dialog = dialogRef.current; dialog.showModal(); return () => dialog.close();}, []);

如果是默认弹窗类,这种也算是元素状态,同样需要对其(弹出)状态进行重置。

3-1)异步请求页面数据处理,处理异步数据渲染useEffect(() => { let ignore = false; async function startFetching() { const json = await fetchTodos(userId); // 这里执行是异步的,所以第一次执行到此处的时候组件已经被卸载了 // 此时的 ignore 已经被 return 里面的方法置为 true 了 // 所以这里第一次执行的时候不执行 setTodos(json) // setTodos 其实是在第二次执行的时候才触发 if (!ignore) { setTodos(json); } } startFetching(); return () => { ignore = true; };}, [userId]);

如上代码,对于异步请求数据并渲染这一类。 我们可以设置一个 标识位,做到对 请求返回的数据 仅做一次处理与渲染setTodos(json)。 codesandbox 测试代码段

3-2)异步请求页面数据处理,处理接口请求

上面的方法虽然仅会渲染一次,但是请求依然发起了多次。 如果不希望请求多次,也可以使用请求接口数据的缓存方案,对返回数据进行缓存。

const cache = useRef(null);useEffect(() => { let ignore = false; async function startFetching() { if (!cache.current) { cache.current = await fetchTodos(userId); } if (!ignore) { setTodos(cache.current); } } startFetching(); return () => { ignore = true; };}, [userId]);

对于异步请求,除了可以处理渲染频率,还可以对接口的请求本身做缓存。 在前面3-1的基础上,缓存接口返回的数据,下次请求的时候如果已经有缓存数据了就直接用,无须再次发起请求。

4)无须清理类

并不是所有的 useEffect 函数都需要清理,对于一些没有副作用的函数,我们完全可以不做处理

useEffect(() => { const map = mapRef.current; map.setZoomLevel(zoomLevel);}, [zoomLevel]);

如上代码所示,setZoomLevel 方法仅仅是设置一下 Dom 元素的层级。 这种操作无论同时执行多少次都不会有太大的影响,所以对于这一类我们就随他去吧,毕竟线上也不会执行多次。

5)日志 log 上报类useEffect(() => { reportLog({ name: 'viewCount' });}, []);

对于日志上报类,其实也可以算是无须清理类,但是又有点特殊。 因为,对于日志类,首先在开发环境中我们其实是无须进行上报的,毕竟这种日志打上去也没啥用。 当然,如果是要对上报日志本身这个进行调试等必须上报的情形,这种也有三种应对方式:

方式一,在本地开发环境使用 console.log 来代替 reportLog。方式二,取消掉严格模式(StrictMode) 方式三,构建一个 production版本启动,或者将其部署到 QA 环境,部署的时候,指定 production 模式。

借鉴链接:大神地址:epoos

本文链接地址:https://www.jiuchutong.com/zhishi/293020.html 转载请保留说明!

上一篇:“Ninja is required to load C++ extensions”解决方案

下一篇:web网页设计期末课程大作业 HTML+CSS+JavaScript重庆火锅(代码质量好)(web网页设计期末作业猫眼电影首页)

  • 微信粉丝怎样增加、管理与维护(微信粉丝如何快速增加)

    微信粉丝怎样增加、管理与维护(微信粉丝如何快速增加)

  • 腾讯视频能投屏吗(腾讯视频能投屏到投影仪吗)

    腾讯视频能投屏吗(腾讯视频能投屏到投影仪吗)

  • excel表格方格里面打钩怎么做(excel表格方格里倒三角是什么格式)

    excel表格方格里面打钩怎么做(excel表格方格里倒三角是什么格式)

  • 一个手机能同时用两个抖音号吗

    一个手机能同时用两个抖音号吗

  • 微信怎么批量删除聊天记录(微信怎么批量删除朋友圈内容)

    微信怎么批量删除聊天记录(微信怎么批量删除朋友圈内容)

  • 微信面部支付怎么设置(微信 面部支付)

    微信面部支付怎么设置(微信 面部支付)

  • 芒果视频为什么弹幕都没有了(芒果视频为什么那么卡)

    芒果视频为什么弹幕都没有了(芒果视频为什么那么卡)

  • cad圆怎么等分(cad圆怎么等分后怎么测量)

    cad圆怎么等分(cad圆怎么等分后怎么测量)

  • 魅族17多少倍变焦(魅族17pro最高支持多少倍变焦)

    魅族17多少倍变焦(魅族17pro最高支持多少倍变焦)

  • 手机屏幕出现彩色细线(手机屏幕出现彩色斑块怎么消除)

    手机屏幕出现彩色细线(手机屏幕出现彩色斑块怎么消除)

  • 手机通话功能怎么关闭(手机通话功能怎么关闭设置)

    手机通话功能怎么关闭(手机通话功能怎么关闭设置)

  • 序号怎么拉下来都是1(序号怎么拉下来自动排序)

    序号怎么拉下来都是1(序号怎么拉下来自动排序)

  • 淘宝账号被盾过什么意思(淘宝被盾解决方法)

    淘宝账号被盾过什么意思(淘宝被盾解决方法)

  • regedit怎么打开(regedit怎么打开分辨率)

    regedit怎么打开(regedit怎么打开分辨率)

  • 屏幕总成不带框好换吗(屏幕总成不带框怎么解决边框问题)

    屏幕总成不带框好换吗(屏幕总成不带框怎么解决边框问题)

  • 小米8可以用5a数据线吗(小米8可以用5a的充电线吗)

    小米8可以用5a数据线吗(小米8可以用5a的充电线吗)

  • word怎么删除所有所有图片(word怎么删除所有页码)

    word怎么删除所有所有图片(word怎么删除所有页码)

  • 苹果11怎么开个人热点(苹果11怎么开个人模式)

    苹果11怎么开个人热点(苹果11怎么开个人模式)

  • 手机淘宝旺旺发不出去消息(手机淘宝旺旺发的视频在哪里)

    手机淘宝旺旺发不出去消息(手机淘宝旺旺发的视频在哪里)

  • 手机广角镜头怎么用(手机广角镜头怎么安装)

    手机广角镜头怎么用(手机广角镜头怎么安装)

  • 邮箱163密码找回(163邮箱密码找回方法)

    邮箱163密码找回(163邮箱密码找回方法)

  • 蓝牙sbc格式和aac差别(蓝牙sbc aac)

    蓝牙sbc格式和aac差别(蓝牙sbc aac)

  • 百度云网盘账号怎么查(百度云网盘账号申诉)

    百度云网盘账号怎么查(百度云网盘账号申诉)

  • 小米风扇怎么连接小爱同学(小米风扇怎么连接)

    小米风扇怎么连接小爱同学(小米风扇怎么连接)

  • 微信收款的声音在哪里设置(微信收款的声音在哪里打开)

    微信收款的声音在哪里设置(微信收款的声音在哪里打开)

  • airpods2如何设置siri(airpod2怎么设置)

    airpods2如何设置siri(airpod2怎么设置)

  • qq怎么设置闺蜜(QQ怎么设置闺蜜)

    qq怎么设置闺蜜(QQ怎么设置闺蜜)

  • 建筑公司收到预付款怎么开票
  • 限售股在锁定期内卖出
  • 差旅费住宿专票能否抵扣
  • 员工个人承担的保险分录
  • 8000块电脑大概能跑多少分
  • 实收资本资本公积盈余公积均属于投资者投入企业的资本
  • 个人车卖给公司能抵税吗
  • 小规模纳税人印花税减免税优惠政策
  • 小规模纳税人开普票要交税吗
  • 异地经营如何纳税
  • 保险公司赔款可以用子女的二类卡吗
  • 母子公司间资产划拨开免税发票
  • 事业单位财政授权书模板
  • 流动资产投资的特点有
  • 在建工程转固后又发生成本
  • 个人去税务局能开什么类型的发票
  • 劳务分包有执照没资质能开票吗?
  • 自查补缴税款严重吗
  • 增值税影不影响企业利润
  • 商场赠送购物券是真的吗
  • 建安企业核定征收改查账征收后怎么处理账目
  • 结转本月销售成本的会计分录
  • 跨年冲暂估如何做账?
  • w11系统有哪些新功能
  • 购进材料用于在建工程进项税
  • 公司车辆报废收入怎么入账
  • 增值税进项发票不够抵扣怎么办
  • Msssrv.exe - Msssrv是什么进程 有什么用
  • 企业税收有哪些部分组成
  • 未担保余值通俗理解
  • 高新技术企业职工总数
  • 建筑工程企业管理费包括哪些内容
  • 了解的反义词
  • ROS2+cartographer+激光雷达+IMU里程计数据融合(robot_locazation) 建图
  • 工程结算结算gbq文件怎么做
  • mess指令
  • 汇算清缴补交所得税怎么做凭证
  • vue数据加载完成显示页面过渡动画
  • 自产货物进项税抵扣
  • 万元版和十万元版发票图片
  • 不动产作价出资入股登记收件
  • 企业附加税的税率
  • SqlServer 2005/2008数据库被标记为“可疑”的解决办法
  • 增值税发票系统客服电话
  • 税金及附加包括哪些科目
  • 核价人员要对哪些方面的价格进行核定,怎么核?
  • 房地产企业成本核算方法
  • 购进免税农产品进项税额计算
  • 个人如何缴纳公积金和社保费用
  • 装修费一定要摊销吗
  • 工程施工的保险费的账务处理
  • 权益净利率计算公式产权比率
  • 固定资产清理的税率是多少
  • 投资子公司亏损母公司报表怎么做
  • 建安发票是增值税发票吗
  • 预收账款和应收账款可以放在一个账户
  • 电费发票应收电费怎么开
  • 子公司的亏损能算到母公司吗
  • 存储过程失效怎么办
  • linux服务器查找文件命令
  • 如何查看电脑端口号
  • windowsxp教程
  • windows显示内部版本
  • 如何关闭win8.1自动更新
  • win7操作系统的主要功能
  • 怎么把喜欢的图片设置成电脑壁纸
  • 卸载安装软件
  • perl $?
  • 网页设计中的几种齐方式及其特点
  • python操作微信自动发消息
  • node.js ajax
  • python中子类继承父类的静态方法吗
  • openlayers3示例
  • jQuery soColorPacker 网页拾色器
  • 青海国税发票查询系统
  • 四川省职称查询平台
  • 杭州市税务局总局地址
  • 重庆路桥价值
  • 集体土地征收应该有哪些文件
  • 湖北省叉车考试题库
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设