useEffect、useLayoutEffect 和 useEffectEvent:React 中資料取得 Hook 的比較
React hooks 是管理 React 元件中副作用的有效方法。用來處理副作用的三個最常見的掛鉤是 useEffect、useLayoutEffect 和 useEffectEvent。每個鉤子都有其獨特的用例,因此選擇適合工作的鉤子至關重要。
useEffect 鉤子
效果渲染函數和依賴列表。
效果函數封裝了負責產生副作用的程式碼,而依賴陣列則指示何時應執行該函數。如果依賴項數組仍然沒有內容,則效果函數將僅在元件的初始渲染期間執行。相反,如果依賴數組包含任何更改,則每次修改都會觸發效果函數重新運行。
事實上,使用useEffect
鉤子進行資料檢索的主要說明如下:
import React from "react";
function App() {
const [data, setData] = React.useState([]);
React.useEffect(() => {
fetch("<https://jsonplaceholder.typicode.com/posts>")
.then((response) => response.json())
.then((data) => setData(data));
}, []);
return (
<div className="app">
{data.map((item) => (
<div key={item.id}>{item.title}</div>
))}
</div>
);
}
export default App;
此範例展示了一個功能性 React 元件,稱為「App」元件,它利用「useEffect」掛鉤從外部 API 檢索資料。具體來說,與“useEffect”掛鉤關聯的效果處理程序從 JSONPlaceholder API 獲取示例信息,處理 JSON 響應,然後使用獲得的數據更新“數據”狀態。
考慮到應用程式資料的目前狀態,應用程式會顯示與該資訊中每個對應項目關聯的標題屬性。
useEffect Hook 的特點
該應用程式在設計時考慮到了非同步操作,並在本地合併了此功能,從而在檢索資料時提供無縫體驗。
useEffect
鉤子的使用被安排在給定元件的渲染過程完成之後發生,從而保證所述鉤子在此期間不會阻礙或阻礙使用者介面。
指令提供了一種簡化的方法,透過提供在偵聽器或訂閱完成時自動呼叫的函數來執行清理任務。在高效關閉和釋放資源至關重要的情況下(例如涉及偵聽器或訂閱的情況),此類功能可能特別有用。
useLayoutEffect 鉤子
useLayoutEffect
鉤子的使用與 useEffect
鉤子的功能密切相關;然而,它在 DOM 更改的所有實例之後同步運行。因此,該函數在瀏覽器能夠在螢幕上呈現視覺表示之前執行,從而對於需要精確操作文檔物件模型(DOM)結構和樣式屬性(包括但不限於確定維度)的任務來說非常有利。調整特定元素的尺寸,重新調整元素的尺寸,或透過動畫技術協調所述元素的空間排列。
利用 useLayoutEffect
鉤子,可以修改按鈕組件的尺寸,如下所示:
import React from "react";
function App() {
const button = React.useRef();
React.useLayoutEffect(() => {
const { width } = button.current.getBoundingClientRect();
button.current.style.width = `${width \+ 12}px`;
}, []);
return (
<div className="app">
<button ref={button}>Click Me</button>
</div>
);
}
export default App;
上述程式碼片段利用「useLayoutEffect」功能實用程式將按鈕組件的尺寸擴展了十二個單位。因此,此配置保證在按鈕在使用者顯示裝置上可見之前將調整後的寬度套用至按鈕。
useLayoutEffect Hook的特點
JavaScript 程式碼的同步執行可確保操作依序發生,而不會對使用者介面造成任何中斷。但是,由於某些操作非常耗時,這種方法可能會導致 UI 延遲或阻塞。
DOM 讀取/寫入操作的理想設計是為了立即存取文件物件模型以讀取和寫入數據,特別是當優先考慮在瀏覽器重新繪製過程之前觀察修改時。
useEffectEvent 掛鉤
「useEffectEvent」鉤子的使用為傳統「useEffect」鉤子中固有的具有挑戰性的依賴性問題提供了有效的解決方案。那些精通 useEffect 工作原理的人似乎可能會發現自己正在努力解決其依賴數組的複雜性,這有時需要包含超出正常功能絕對需要的元素。
例如:
import React from "react";
function App() {
const connect = (url) => {
// logic for connecting to the url
};
const logConnection = (message, loginOptions) => {
// logic for logging the connection details
};
const onConnected = (url, loginOptions) => {
logConnection(`Connected to ${url}`, loginOptions);
};
React.useEffect(() => {
const device = connect(url);
device.onConnected(() => {
onConnected(url);
});
return () => {
device.disconnect();
};
}, [url, onConnected]);
return <div></div>;
}
export default App;
目前的程式碼展示了
useEffect
鉤子透過呼叫 connect
方法並建立一個非同步「onConnected」回呼函數來起作用,一旦裝置觸發「onConnected」事件,該函數就會執行。隨後,此回呼執行產生連線訊息的日誌操作。此外,它還提供了退役功能,該功能在組件卸載時生效,從而承擔切斷與設備連接的責任。
DependencyArray 包含 URL 和稱為「onConnected」的事件處理程序。每次渲染 App 元件時,它都會動態產生這個特定的函數。因此,React 鉤子「useEffect」會經歷一個迭代過程,其中其主要目標是重複更新 App 元件的狀態。
解決 useEffect 循環問題的有效方法之一是利用 useEffectEvent 掛鉤,它可以提供簡化的解決方案,而不會給依賴項數組帶來額外的不必要的值負擔。
import React from "react";
function App() {
const connect = (url) => {
// logic for connecting to the URL
};
const logConnection = (message, loginOptions) => {
// logic for logging the connection details
};
const onConnected = React.useEffectEvent((url, loginOptions) => {
logConnection(`Connected to ${url}`, loginOptions);
});
React.useEffect(() => {
const device = connect(url);
device.onConnected(() => {
onConnected(url);
});
return () => {
device.disconnect();
};
}, [url]);
return <div></div>;
}
export default App;
透過利用useEffectEvent
鉤子來包裝onConnected
函數,我們確保message
和loginOptions
參數在傳遞到useEffect
鉤子時始終是最新的。因此,後者不再依賴前者或提供給它的任何參數。
當使用useEffect
鉤子時,依賴一個特定的值來觸發效果是有利的,儘管事實上效果需要額外的值,而這些值可能不希望作為useEffect
中的依賴項。
useEffectEvent Hook 的特點
該系統擅長處理事件觸發的後果。
useEffect
鉤子的使用與onClick
、onChange
等事件處理函數不相容,因為這些事件是由使用者互動觸發的,而不是由 React 監視變化的反應性依賴項。
useEffect
鉤子是一個強大且多功能的工具,用於管理功能組件中的副作用,截至React 18 版本,它仍然是一個實驗性功能。應該注意的是,它的可用性可能因React 的不同版本或構建而異。
何時使用哪一個 Hook?
每個資料獲取鉤子都有其獨特的適用性,具體取決於具體情況。
使用 React 中的 useEffect 鉤子提供了一個合適的解決方案來獲取和更新元件內的數據,因為它允許高效管理非同步操作,同時保持乾淨且有組織的程式碼庫。
當需要以需要立即呈現變更的方式對文件物件模型 (DOM) 進行直接修改時,建議使用 useLayoutEffect 。此函數透過確保在初始渲染之後和任何後續更新或回流發生之前執行指定的操作,可以有效地處理此類任務。
使用useEffect
鉤子進行輕量級操作不會阻礙使用者介面,從而可以輕鬆方便地執行它們。
事件驅動副作用的利用可以透過使用useEffectEvent
鉤子來捕獲和處理事件,以及使用useEffect
鉤子來執行任何必要的副作用來回應這些事件來實現。
有效處理副作用
React hooks 的使用揭示了廣泛的潛力,並且理解 useEffect、useLayoutEffect 和 useEffectEvent hooks 之間的差異可以極大地影響人們管理副作用和 DOM 操作的方式。為了建立以使用者為中心的軟體程序,必須考慮這些鉤子的特定先決條件和後果。