一、簡介
React Hooks是React 16.8推出的新特性,是一種更加優雅、簡潔的處理組件狀態和邏輯的方式,幹掉了原有的Class組件,讓函數組件具有了更加強大的能力。
react-hooks/exhaustive-deps是React Hooks中的一個重要概念,用於在useEffect Hook中控制副作用執行的依賴項,使代碼更加健壯、穩定。
二、為什麼需要控制副作用執行的依賴項
在使用useEffect Hook時,React會在DOM更新前執行useEffect副作用函數中的代碼,以保證頁面的正確性和流暢性。由於useEffect是基於函數式編程的思想實現,React並不能像Class組件中的生命周期函數一樣自動清理副作用代碼的引用,這就需要我們手動控制副作用執行的依賴項。
舉個例子:一個簡單的計數器函數組件,每點擊一次按鈕,計數器就會+1,並在useEffect中輸出計數器的值:
import React, { useState, useEffect } from 'react';
function Counter() {
const [count, setCount] = useState(0)
useEffect(() => {
console.log('count:', count)
})
return (
<div>
<p>count: {count}</p>
<button onClick={() => setCount(count + 1)}>+1</button>
</div>
);
}
但是,運行後我們發現,每點擊一次按鈕,控制台就會輸出當前的count值,即使count並沒有改變。這是因為,useEffect的執行是基於引用依賴,而每次點擊按鈕的時候,函數組件會被重新渲染,useEffect重新執行,此時的count依然是引用上一個count值的地址,所以console輸出的值並沒有改變。
這時候,就需要我們想辦法控制useEffect的依賴項,規避這種無用執行的問題。
三、如何控制副作用執行的依賴項
1. 不指定依賴項
當useEffect的依賴項傳空數組[]時,表明useEffect不依賴任何state或prop,僅在組件掛載和卸載時執行副作用代碼。
useEffect(() => {
console.log('component did mount');
// 清理操作
return () => {
console.log('component will unmount');
}
}, []) // 傳空數組
這種方式適用於只需要在組件掛載和卸載時執行副作用代碼,而不需要根據state或prop的變化執行的場景。
2. 指定部分依賴項
當useEffect的依賴項為指定的state或prop時,每次state或prop發生變化時,useEffect都會執行副作用代碼。
useEffect(() => {
console.log('count:', count)
}, [count]) // 指定count為依賴項
這種方式適用於只需要根據指定的state或prop變化來執行副作用代碼的場景。
3. 指定所有依賴項
當useEffect的依賴項為所有state或prop時,每次任意一個state或prop發生變化時,useEffect都會執行副作用代碼。在依賴項比較多的情況下,這種方式會造成性能問題,應當慎用。
useEffect(() => {
console.log('effect:', count, size)
}, [count, size]) // 指定所有依賴項
四、控制依賴項出錯的問題
雖然指定依賴項可以避免掉無用執行的問題,但是如果指定的依賴項不全、不正確的話,依然會帶來錯誤和性能問題。
繼續看一個例子:一個定時器函數組件,每1秒鐘計數器+1,然後在useEffect中輸出計數器的值。當props.count發生變化的時候,就會清空計數器。
import React, { useState, useEffect } from 'react';function Timer(props) {
const { count } = props;
const [num, setNum] = useState(0);
let timer = null;
useEffect(() => {
startTimer();
return () => clearInterval(timer);
}, []);
useEffect(() => {
console.log('num:', num);
if (count !== 0) {
setNum(0);
}
}, [count]);
function startTimer() {
timer = setInterval(() => {
setNum(num => num + 1);
}, 1000);
}
return (
num: {num}
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hk/n/312650.html