React hooks 已於 6 年前發布,但直到今天,我們仍然可以看到錯誤的發生,即使是高級 React 工程師也是如此。在最新版本的 React 文件中,核心團隊付出了很大的努力來教導 useEffect 的錯誤用例,但在實際專案中錯誤仍然不斷發生。
在這篇文章中,讓我們嘗試不同的方法。讓我們了解 React 與派生的關係以及為什麼應該更多地使用它。
React 並不是完全響應式的,但最終,對於創建應用程式的開發人員來說,這並不重要。這裡的區別在於,React 遵循的粗粒度方法創建了重新渲染的必要性,以真正識別狀態轉換所建立的變更。
所以,考慮一個像這樣的簡單 React 元件:
function Example() { const [count, setCount] = useState(0) const text = `count is ${count}`; return ( <button onClick={() => setCount((count) => count + 1)}> {text} </button> ); }
當我們更改計數狀態時,呼叫 setCount,我們會更新狀態值並安排重新渲染。好吧,React 將重新渲染這個元件,再次呼叫它。此時,如果我問 React 渲染發生了什麼變化,答案應該是什麼?
可能是一個謙虛的「我不知道」。
React 不會像其他細粒度反應式函式庫那樣使用複雜的資料結構來管理其依賴項來追蹤其狀態。 React 需要再次呼叫該元件。在這個新呼叫中,建立的計數常數將具有新值,在其上方我們將使用字串建立一個新常數,例如 “count is 1”,如果計數值變更為 1。
然後 JSX 將透過一次變更來產生其結構,按鈕內部文字不是 「計數為 1」,React 會進行協調過程,識別此變更並將其套用到真實 DOM。顯而易見,對吧?
此時,如果我問 React 發生了什麼變化,它可能會回答:「範例元件中的按鈕文字」。
但是等等,文字常數呢?它也發生了變化,為什麼它創建的 v-dom (我知道這個術語的問題,但它通常是這樣稱呼的)結構很重要?
對於 React,你內部建立的變數和常數並不重要。重要的是狀態改變,然後是元件呼叫的回傳。
中間的所有內容都是建立視圖結構過程的一部分。當然,所有這些資料都會影響傳回的 JSX,這就是 React 模型的要點,關心元件呼叫的結果並根據視圖相應地更新 DOM。
您可能會看到 React 模型的簡化:
function Example() { const [count, setCount] = useState(0) const text = `count is ${count}`; return ( <button onClick={() => setCount((count) => count + 1)}> {text} </button> ); }
查看狀態函數的結果。在這種情況下,視圖是根據狀態變化的派生。因此,對於這個術語和內部組件數據,React 是一個推導機。
您在元件內建立的每個變數和常數在該元件呼叫期間都將處於活動狀態。在我們上面使用的範例中,範例元件的每次重新渲染都會建立一個新的常數文字。如果我需要基於某些道具或狀態的新值,它只會在計算中使用這些狀態和道具來建立一個新變數。
讓我們以 React 文件為例:
view= f(state)
我們這裡遇到一些問題。首先,國家的本質。
為什麼我們在應用程式中需要這樣的本地狀態?保留資料並允許用戶更改它。 fullName 狀態不是由使用者更改,而是由 useEffect 更改。它正在利用其他狀態來創造新的價值。同樣,在 React 中,我們在元件內部建立的每個變數和常數都可以使用 states 和 props 來計算其值:派生,React 的預設行為.
這個例子還有另一個問題,關於運行時。在這種情況下,在第一次渲染中,fullName 值將為空字串。 React 將取得該元件的 JSX 返回,將其渲染到 UI,遵循瀏覽器繪製過程,然後呼叫元件的 useEffects。此時我們將進行 setfullName 調用,它將安排新的重新渲染。 React 將再次呼叫該元件,現在完整名稱為 Taylor Swift,然後使用新的文字值更新 UI。
就運行時而言,您正在進行 2 次渲染,其中一次是不必要的,且資料錯誤。它在性能和穩定性方面更差,因為用戶會看到該值為空,並且可以被視為視覺錯誤。
所以,依照React的推導模型,我們可以簡單修改為:
function Form() { const [firstName, setFirstName] = useState('Taylor'); const [lastName, setLastName] = useState('Swift'); // ? Avoid: redundant state and unnecessary Effect const [fullName, setFullName] = useState(''); useEffect(() => { setFullName(firstName + ' ' + lastName); }, [firstName, lastName]); //... return <span>{fullName}</span>; }
現在我們只有 1 個渲染,避免了不必要的渲染。我們將避免僅使用推導來使用效果。每次重新渲染時都會使用最新版本的狀態值進行更新。
對,在本例中只需使用 useMemo,新增與 useEffect 上使用的相同的依賴項陣列。 React 的記憶模型只是避免預設行為的一種方法,即在每次重新渲染時創建一個新的派生。使用 useMemo,您可以手動追蹤狀態和 props,如果其中一些狀態和 props 發生變化,只需再次建立派生。
useEffect 對於值變更的外部同步是必要的。在UI 開發中,很少有這種情況有意義,因為通常外部變更(例如伺服器API 呼叫)發生在使用者操作上(順便說一下,我們正在建立使用者介面),所以這些將發生在事件處理程序上,而不是在useEffect 中。
如果您使用 useEffect 來更新狀態,也許您可以使用派生進行相同的更新,從而避免之前提到的所有問題。
如果推導不起作用,或者你遇到了少數特定情況之一,或者國家的設計或解決方案本身有問題。沒有問題,但在這些情況下,最好檢查組件並避免組件代碼將來出現問題。
這是 React 中推導的基礎知識,但我們這裡缺少一些東西。
當我需要進行非同步推導(例如簡單的 GET 請求)時會發生什麼,該請求使用某些狀態作為參數並且每次狀態更改時都需要重新計算?
這是下一篇文章的主題。
再見!
以上是你不知道 React 的推導的詳細內容。更多資訊請關注PHP中文網其他相關文章!