[react] 从useEffect中死循环理解useEffect 和useCallback的使用


原文参考地址

原文阐述了在useEffect中如果依赖为一个一直变化着的状态时,它将陷入一个死循环。而在我的实验中,发现如果setTest设置的不是一个常量值时,就会出现警告,提示需要将init函数也加入useEffect的依赖中。

import { useEffect, useState } from "react";

export default function InfiniteLoopUseEffect() {
  const [test, setTest] = useState(1);
  const init = () => {
    // setTest(2);
    setTest(test + 1);
  };
  useEffect(() => {
    init();
    console.log("kkk", test);
  }, [test]);

  return null;
}

image
这也是可以理解的,如果是setTest为一个常量,那么整个函数就是一个纯函数,不依赖任何外物变化,正正当当的一个不可变量。

紧接着,我就按照提示加上了init依赖,不可避免,加了init,仍旧无法避免死循环的结果。
image
此时,终端又出现了警告,init函数每次都会随着render变化,本身init函数就用了能刺激render变化的东西。可以尝试,把它放在useEffect或者useCallback中。
放在useEffect中,没什么用处,useEffect依赖的东西,时时刻刻都在变化,放在useCallback中可以试试。事实上,如果为”setTest(2)“,如果useEffect的依赖中加入了init函数,反而还会出现这个警告,可能本身当依赖中出现函数,就容易触发这个警告。

一开始,我并没有想过给useCallback加入依赖,就这样,神奇的事发生了,无限循环就这也终止了!停在test为2的时候。

仔细分析useCallback的作用,将useCallback函数缓存到内存中,保持不变,只有当依赖变化时,useCallback才会更新。此时,是没有依赖的,那就说明,useCallback中的东西都不会变化,即使是状态test,它算是比较特别的了,也是不能变化的。所以,init的函数只加载了一次,其中的test一直是原来的那个test=1,所以,每次执行时,新的test依然还会是2。这又回到了“setTest(2)”的情况。

==================================================================

当把2换成对象或者是数组时(数组是一种特殊的对象,key=0,1,2,3...),还是会无限循环,因为每次新建的对象,都是不同的对象。
image

对象存放在堆内存中,获取的对象实际上的内容是对象所在地址,由于每次对象都是new出来的所以这个地址值是不同的。对象引用与地址值的对应关系,是存放在栈内存中。字面量的数字或字符串,直接就是一个引用和它的内容,对比内容,自然都是相等的。
image
image
可以预见,对比依赖变化,采用的方式是通过”==“进行比较的。


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM