React Hooks:Effect无限回调踩坑

8 篇文章 0 订阅
1 篇文章 0 订阅

场景

我的目的是通过Effect来模拟组件的componentDidMount,在渲染完成之后,通过setTimeout来处理操作,向keyIndex中push一个新的元素,并更新keyIndex,但是这个操作我确定只会执行一次。
错误代码如下:

  const [keyIndex, setKeyIndex] = React.useState([]);
  React.useEffect(() => {
  		setTimeout(() => {
  		console.log('err log')
      	let array = [].concat(keyIndex);
		let key = timeLine[0].id;
     	 array.push(key);
     	 setKeyIndex(array)
     	 },2000);
  }, [setKeyIndex]);

代码中我加了一句console.log('err log') ,在组件被执行之后,控制台无限输出err log

问题原因

在Hooks中,虽然可以通过向useEffect传递第二个参数(此处我是在结尾传递了[setKeyIndex]),来达到在传递的数组没有变化时,不对组件进行render操作。
但是这个第二个参数是有限制的—这里的问题就是,第二个参数是引用类型

什么是引用类型:

  • 值类型(基本类型):数值(number)、布尔值(boolean)、null、undefined、string(在赋值传递中会以引用类型的方式来处理)。
  • 引用类型:对象、数组、函数。
根源

useEffect会比较前一次渲染和后一次渲染的值,即使两个值在数值上是相等的,但是在堆栈中对应的地址并不相同,所以 === 操作的时候,值肯定为false。所以引用类型比较不出来数据的变化,会不停地得到false值,并对组件进行render,造成死循环。

解决方法

  • useRef
	const keyIndexRef = useRef(keyIndex);
 	keyIndexRef.current = keyIndex;

通过useRef,将keyIndex数据绑定到keyIndexRef.current上,此时的keyIndexRef是一个可变值盒子,他自身都是可以被更改的。useRef的特点是会在每次渲染时返回同一个 ref 对象,这就解决了我们的render前后数据始终不会相等(===)的问题。

在我这里,修改后的代码如下:

React.useEffect(() => {
    setTimeout(() => {
      let array = [].concat(keyIndexRef.current);
      let key = timeLine[0].id;
      array.push(key);
      setKeyIndex(array);
      });
   },[])
  • 通过setData 接收函数作为参数,并利用闭包和参数来实现数据更新
    用一个类似的例子来进行举例
const [flag, setFlag] = useState(false);
function dealClick() {
        setFlag(!flag);

        setTimeout(() => {
            setFlag(flag => !flag);
        }, 2000);
    }
return (
        <button onClick={dealClick}>{flag ? "true" : "false"}</button>
    );

另外,如果useEffect不放置任何参数,则在组件化的过程中会且仅执行一次。但是如果还是出现改变引用类型的错误的话,每次执行都会拿到的keyIndex的默认初始值,实际setKeyIndex 的结果并不会被更新上去

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值