Shyno
Don't be shy,no problem!

前言:我在我的另一篇博客中有说道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多次进入的问题

 

   

posted on 2021-12-03 11:11  Shyno  阅读(1341)  评论(0编辑  收藏  举报