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