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]);