hooks中,useEffect无限调用问题产生的原因
前言:我在我的另一篇博客中有说道useEffect监听对象或者数组时会导致useEffect无限执行,并给予了解决方案-useEffect无限调用问题 .后来我想从其产生根源去理解并解决这个问题.
原因:
错误代码
const [test, setTest] = useState({ name: '小明', age: '18' });
const init = () => {
setTest({ name: '小红', age: '16' });
};
useEffect(() => {
init();
console.log('kkk', test);
}, [test]);
以上代码,如果执行,会发现useEffect会无限执行.
分析原因有以下几个方面.
1.引用数据类型的比较是地址,即"引用"来比较的.
2.js每次创建对象都会产生一个新的地址.
简单来说就是
console.log({}==={}) //false
但是
let a = {}
let b = a
console.log(a===b) //true
也就是说,问题出在这行代码
const init = () => {
setTest({ name: '小红', age: '16' });
};
这个{name:'小红',age:'16'}其实每次都是一个新的对象,在useEffect中比较的时候,每次都会拿到一个新的引用,所以useEffect每次都会执行,每次执行又拿到一个新的test.于是就变成了无限执行了.
解决方案:
所以我们可以用一下方案去避免这个问题的产生.
1.固定"引用".
即我们只用一个引用
let b = { name: '小明', age: '18' };
let a = { name: '小红', age: '16' };
const Test= () => {
const [test, setTest] = useState(b || { name: '小明', age: '18' }); //useState的默认值并不会更新,所以不会产生新引用
const init = () => {
setTest(a); //a的值不会变
};
useEffect(() => {
init();
console.log('kkk', test);
}, [test]);
}
2.固定"值"
即我们只要保证对象里面的属性和值是一样的就行
const [test, setTest] = useState({ name: '小明', age: '18' });
const init = () => {
setTest({ name: '小红', age: '16' });
};
useEffect(() => {
init();
console.log('kkk', test);
}, [JSON.stringify(test)]); //只要对象里面的键和值是一样的,JSON.stringify(test)的值就不会变
应该还有其他方案,但大致方向就是这两类.
因为hooks的特性会导致组件代码重复执行,所以类似解构的默认值会重复给.假如使用的dva又不在models里面给默认值而是在hooks里给的话,监听这个变量就可能出现这个问题
const { btn={}} = useSelector((state) => state.buttonList);//假如buttonList里面btn并没有默认值,那这里监听btn就会出现useEffect多次进入的问题
hooks中,useEffect无限调用问题产生的原因的更多相关文章
- useEffect无限调用问题
1.useEfect()的基本用法 const [test,setTest] = useState(1) const init=()=>{ setTest(2) } useEffect(()=& ...
- React Hooks中父组件中调用子组件方法
React Hooks中父组件中调用子组件方法 使用到的hooks-- useImperativeHandle,useRef /* child子组件 */ // https://reactjs.org ...
- hooks中,useState异步问题解决方案
问题描述: 在hooks中,修改状态的是通过useState返回的修改函数实现的.它的功能类似于class组件中的this.setState().而且,这两种方式都是异步的.可是this.setSta ...
- JavaScript 中的尾调用
尾调用(Tail Call) 尾调用是函数式编程里比较重要的一个概念,它的意思是在函数的执行过程中,如果最后一个动作是一个函数的调用,即这个调用的返回值被当前函数直接返回,则称为尾调用,如下所示: f ...
- java 8中构建无限的stream
目录 简介 基本使用 自定义类型 总结 java 8中构建无限的stream 简介 在java中,我们可以将特定的集合转换成为stream,那么在有些情况下,比如测试环境中,我们需要构造一定数量元素的 ...
- java中实现无限层级的树形结构
本文展示了两个实现方法的代码.两个代码的实现方法不同,代码2更为简单. 先看一下最后实现的结果: 最后结果-json 代码1: 实现过程: 1.传入一段json字符串 2.将字符串转换成对象存入节点列 ...
- Hooks中的useState
Hooks中的useState React的数据是自顶向下单向流动的,即从父组件到子组件中,组件的数据存储在props和state中,实际上在任何应用中,数据都是必不可少的,我们需要直接的改变页面上一 ...
- Java中是否可以调用一个类中的main方法?
前几天面试的时候,被问到在Java中是否可以调用一个类中的main方法?回来测试了下,答案是可以!代码如下: main1中调用main2的主方法 package org.fiu.test; impor ...
- 在IIS7.5中ASP.NET调用cmd程序拒绝访问决绝方法小记
前言 昨天利用Github的Webhook实现自动部署站点,其中要调用命令行(cmd.exe)程序执行shell脚本. 在本地测试没有任何问题,部署到服务器之后,发现错误信息:访问拒绝. 问题 没有权 ...
随机推荐
- java-UDP协议接收和发送数据
UDP发送数据的步骤: A:创建发送端的Socket服务对象 B:创建数据,并把数据打包 C:通过Socket对象的发送功能发送数据包 D:释放资源 public class SendDemo { ...
- [hdu7012]Miserable Faith
类似于[NOI2021]轻重边的逆过程,操作1即为对$u$执行access(根为1),$dist(u,v)$即为$u$到$v$的虚边数 对前者用LCT维护,并记录轻重边的切换,显然切换总量为$ ...
- 洛谷 P6570 - [NOI Online #3 提高组] 优秀子序列(集合幂级数+多项式)
洛谷题面传送门 首先 \(3^n\) 的做法就不多说了,相信对于会状压 dp+会枚举子集的同学来说不算困难(暴论),因此这篇博客将着重讲解 \(2^nn^2\) 的做法. 首先如果我们把每个 \(a_ ...
- Codeforces 1264F - Beautiful Fibonacci Problem(猜结论+找性质)
Codeforces 题面传送门 & 洛谷题面传送门 一道名副其实(beautiful)的结论题. 首先看到这道设问方式我们可以很自然地想到套用斐波那契数列的恒等式,注意到这里涉及到 \(F_ ...
- 使用mamba加快conda安装软件速度?
conda是个安装软件的神器,但镜像不稳定,下载安装软件的速度有时很慢.对于几十Mb甚至上百Mb的软件往往下不动,下了半天可能失败. 找了一个叫mamba的加速神器,可以用来并行下载和安装,大大加快速 ...
- MYSQL5.8----M4-5
mysql> CREATE TABLE joson( id INT AUTO_INCREMENT PRIMARY KEY, context JSON NOT NULL)// Query OK, ...
- phpMyAdmin简介及安装
phpMyAdmin是一个MySQL数据库管理工具,通过Web接口管理数据库方便快捷. Linux系统安装phpMyAdmin phpMyAdmin是一个MySQL数据库管理工具,通过Web接口管理数 ...
- Linux搭建yum仓库
1.安装nginx 2.为nginx搭建共享目录 3.安装createrepo,创建存储库 4.客户端测试 1.安装nginx yum list |grep nginx #查看是否有可用的nginx包 ...
- Apache RocketMQ分布式消息传递和流数据平台及大厂面试宝典v4.9.2
概述 **本人博客网站 **IT小神 www.itxiaoshen.com 定义 Apache RocketMQ官网地址 https://rocketmq.apache.org/ Latest rel ...
- WebRTC本地分享屏幕,录制屏幕
WebRTC有分享屏幕的功能.使用的是getDisplayMedia方法.用户同意分享屏幕后,可以拿到视频流. 再结合MediaRecorder和Blob,把视频流数据存下来,就能得到录制屏幕的视频. ...