05 useEffect高级用法
所谓高级用法,只不 过是一些深层知识点和实用技巧,你甚至可以把本章当做对前面知识点的一个巩固和学习。
让useEffect只在挂载后和卸载前执行一次
让我们实现 “04 useEffect基础用法” 中 举例2 提到的功能。
组件需求:
1、若某类组件中有变量a,默认值为0,当组件第一次被挂载后或组件重新渲染后,将网页标题显示为a的值。
2、当组件第一次被挂载后执行一个自动累加器 setInterval,每1秒 a 的值+1。为了防止内存泄露,我们在该组件即将被卸载前清除掉该累加器。
需求分析:
关于自动累加器的操作,只关联 “组件挂载后和组件卸载前” 这2个生命周期函数中,那useEffect还包含了每次组件重新渲染后,这该怎么办?
答:useEffect函数的第2个参数表示该依赖关系,将useEffect的第2个参数,设置为空数组 [],即表示告诉React,这个useEffect不依赖任何变量的更新所引发的组件重新渲染,以后此组件再更新也不需要调用此useEffect。
这样就可以实现只在第一次挂载后和卸载前调用此useEffect的目的。
import React, { useState,useEffect} from 'react';
function Component() {
const [a, setA] = useState(0);//定义变量a,并且默认值为0
//定义第1个useEffect,专门用来处理自动累加器
useEffect(() => {
let timer = setInterval(() => {setA(a+1)},1000);// <-- 请注意这行代码,暗藏玄机
return () => {
clearInterval(timer);
}
}, []);//此处第2个参数为[],告知React以后该组件任何更新引发的重新渲染都与此useEffect无关
//定义第2个useEffect,专门用来处理网页标题更新
useEffect(() => {
document.title = `${a} - ${Math.floor(Math.random()*100)}`;
},[a])
return <div> {a} </div>
}
export default Component;
以上代码实际运行正确吗?
答:不正确!
?
小朋友,脸上是否有很多问号???
实际运行会发现,当组件挂载后,确实会执行一次 setA(a+1)
,a 的值修改为了 1,然后... a 的值一直为 1,并没有继续累加。
上述代码会收到react的一个错误警告提示:Either include it or remove the dependency array. You can also do a functional update 'setA(a => ...)' if you only need 'a' in the 'setA' call.
该错误警告意思是:如果你确认你传入的第2个参数是空数组,那么你可能会用到 setA(a => ...)
这种方式来更新a的值。
问题出在哪里?
让我们再看看那行有玄机的代码:
let timer = setInterval(() => {setA(a+1)},1000);
再看看 react 给我们的错误警告提示:You can also do a functional update setA(a => ...)
if you only need 'a' in the 'setA' call. 你可能会用到 setA(a => ...)
这种方式来更新a的值。
setA(a => ...)
这是在 “03 useState高级用法”中,解决数据异步 时讲的更新方式。
那我们就按照提示,将那行代码修改为:
let timer = setInterval(() => {setA(a => a+1)},1000);
再次执行,错误提示警告没有了,组件也完全按照我们的预期来执行了。react自带的语法检查真的好智能。