useEffect(副作用)通过一个参数来实现模拟class组件的componentDidMount、componentWillUnmount还有componentDidUpdate这几个生命周期函数
无阻塞更新:因为他是在组件挂载之后执行操作,比如请求数据,他是在组件挂载完了以后才执行数据请求,这样就算请求失败了,页面也能正常显示,不会报错;
同一个组件可以多次使用useEffect。
第一种:第二个参数不传值
相当于是监听页面的变化,只要页面有更新,都会执行。
注意:不能在这个函数体内执行页面更新操作,否则会陷入死循环
import React, { useEffect, useRef, useState, useReducer, useMemo } from 'react';
export default function HookDemo(props) {
let [num, setNum] = useState(0);
useEffect(() => {
// 这个是监听的页面的变化,只要页面有state变化就会执行,不能在这个函数体内执行页面更新操作,否则会陷入死循环。
// 类似class组件的componentDidUpdate
console.log('页面监听');
});
return (
<div style={{ padding: 30 }}>
<div style={{ marginTop: 30 }}>
{/* useEffect */}
<h2>useEffect</h2>
<h2>你点了我{num}次了</h2>
<button onClick={() => setNum(num + 1)}>点击</button>
</div>
</div>
);
}
第二种:第二个参数传[]
表示的是它不监听页面数据的变化,只有在页面初始化和销毁之前会执行;
执行的是类似于class组件的componentDidMount和componentWillUnmount两个生命周期;
useEffect(() => {
// 类似componentDidMount
console.log('初始化一下');
return () => {
// 类似componentWillUnmount
console.log('什么都不监听的时候return的函数');
};
}, []);
第三种:第二个参数传具体的值
监听第二个参数数组内所传的值,当对应的state有更新时触发。
注意:这里的执行顺序其实不是先执行上一次useEffect return的函数,而是先正常执行下一次状态更新然后再执行上一次的effct,然后再执行,下一次的effct。因为大多数情况下,effct不会阻塞页面的更新。
useEffect(() => {
// 这个的执行顺序是:先执行return里的函数,再执行外部函数体内的函数,return里获取到的num未更新num前的数据。
console.log('监听num变化');
console.log('函数体内获取的num', num); // 函数体内获取的num 1
return () => {
console.log('监听num的时候return的函数');
console.log('return获取的num', num); // return获取的num 0
};
}, [num]);
effct其实是组件输出的一部分,单次渲染范围内,effct里的props和state是保持不变的。
effects会在每次渲染后运行,并且概念上它是组件输出的一部分,可以“看到”属于某次特定渲染的props和state。就是只要组件有更新,useEffect都是作为组件输出的一部分。
在单次渲染的范围内,props和state都保持不变。
这一点上,函数式组件和class组件是不一样的,因为class组件做了处理,this.state始终是指向最新的值,而不是属于某次特定渲染的值。
const lateInputValue = useRef(inputVal);
useEffect(() => {
setTimeout(() => {
console.log(`延时获取inputval的值:${inputVal}`);
// 延时获取inputval的值:2 延时获取inputval的值:23 延时获取inputval的值:234
}, 3000);
// 用ref可以打破这种单次独立渲染,因为ref始终指向的是最新的inpuval的值,所以在定时器范围内更改了inputval的值,那么ref获取到的就是最新的状态值。
lateInputValue.current = inputVal;
setTimeout(() => {
console.log(`验证一下lateInputValue是几? ${lateInputValue.current}`);
// 验证一下lateInputValue是几? 234 验证一下lateInputValue是几? 234 验证一下lateInputValue是几? 234
}, 3000);
}, [inputVal]);