我問這個問題是為了確認我對某些概念的理解。
React 檔案強調包含 useEffect() 回呼中使用的所有依賴項。如檔案中所述:
否則,您的代碼將參考先前渲染中的陳舊值。
我有點理解這種解釋的來源。但讓我擔心的是“陳舊價值”部分。由于缺少依賴項,我看不到任何可能的方式出現陳舊值。我的論點也得到了檔案中的內容的支持:
有經驗的 JavaScript 開發人員可能會注意到,傳遞給 useEffect 的函式在每次渲染時都會有所不同。這是故意的。事實上,這就是讓我們從效果內部讀取計數值而不必擔心它變得陳舊的原因。
就我的理解,如果我們錯過了列出依賴項,則該效果將不會在由該依賴項更改引起的渲染后運行,因為 React 認為效果不依賴于它。如果我猜測一下,可能是檔案參考過時資料時的情況。事實上,這些資料在效果代碼中已經過時了。但是,效果回呼不會首先運行。在效果運行之前,我不會注意到資料已經過時。如果這很重要,我會首先弄清楚為什么效果沒有運行并解決問題。我不會因為資料過時而感到困惑,而是會因為效果不會運行而感到困惑。
更重要的是,讓我們假設效果在由另一個依賴項更改引起的渲染之后運行。在這種情況下,即使我們錯過了一個依賴項,由于前面提到的關閉原因,我們也不會讀取過時的資料。我做了一些實驗來證實這一點:
export default function App() {
const [count1, setCount1] = useState(0);
const [count2, setCount2] = useState(10);
useEffect(() => {
console.log(count2);
}, [count1]);
return (
<div className="App">
<div>
Count1: {count1}
<button onClick={() => setCount1(count1 1)}>increase</button>
</div>
<div>
Count2: {count2}
<button onClick={() => setCount2(count2 1)}>increase</button>
</div>
</div>
);
}
只要效果運行,我們總是得到最新的count2。那么我的理解成立嗎?
我想知道為什么 React 如此推薦包含所有依賴項。人們通常使用依賴陣列來繞過一些效果運行。如果他們省略了依賴項,那很可能就是他們想要的。如果是失誤,他們會很容易注意到效果沒有運行并采取行動。
uj5u.com熱心網友回復:
您的示例代碼在一個極其簡單的場景中顯示了最簡單的示例。默認情況下,useEffect將在組件的每次重新渲染上運行。使用依賴陣列,內部函式僅在這些值之一發生變化時運行。我個人遇到過這樣的情況:我忘記了一個依賴項,我的效果被觸發了,我的函式中的一個值有過時的資料。這可能是因為有幾個程序同時進行,當一個更改觸發了效果,而另一個資料還沒有趕上時。切換到useReducer用于同時控制多個位的狀態而不是 multiple useState,在某些情況下有所幫助,但最終依賴陣列使其保持一致。另外(我還沒有證實這一點),框架代碼useEffect 可能會大量使用閉包,因此,再次確保它在程序中的正確時刻參考資料點。
uj5u.com熱心網友回復:
我稍微修改了您的示例以顯示過時的值。
效果通常用于異步原因,所以這并不罕見。
基本上它歸結為閉包,useEffect 的第一次渲染將在 count1 和 count2 上創建一個閉包,如果效果沒有在所有依賴項上重新運行,那么這些閉包將保持(陳舊)。
單擊count1then 意味著再次呼叫 useEffect,創建 setInterval 的一個新實體,并帶有 count1 和 count2 的全新(非陳舊)副本。由于 count2 不在依賴陣列中,單擊 oncount2將意味著不會創建新的 setInterval,并且 count1 和 count2 的舊副本保留在記憶體中。
公平地說,這可能是 Hooks 的一個難以理解的領域。很容易將 Hook 組件視為具有資料的類是物件的一部分。但實際上鉤子組件只是渲染函式,useState / useEffect 等,是一種側面加載到渲染函式管道中的組件。相比之下,React 類組件的資料與物件實體一起存盤,因此this.xyz永遠不會過時。
const {useState, useEffect} = React;
function App() {
const [count1, setCount1] = useState(0);
const [count2, setCount2] = useState(10);
useEffect(() => {
const tm = setInterval(() => {
console.log(count1, count2);
}, 1000);
return () => clearInterval(tm);
}, [count1]);
return (
<div className="App">
<div>
Count1: {count1}
<button onClick={() => setCount1(count1 1)}>increase</button>
</div>
<div>
Count2: {count2}
<button onClick={() => setCount2(count2 1)}>increase</button>
</div>
</div>
);
}
ReactDOM.render(<App/>,document.querySelector('#mount'));
<script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<div id="mount"></div>
<p>Increase count2, see the console not update until you increase count1,.</p>
<p>Add count2 to the dependancy, and then everything will keep in sync</p>
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/354024.html
標籤:javascript 反应 反应钩子 使用效果
