useInsertionEffect
允許在任何佈局 Effects 觸發之前將元素插入 DOM 中。
useInsertionEffect(setup, dependencies?)
參考
useInsertionEffect(setup, dependencies?)
呼叫 useInsertionEffect
在任何可能需要讀取佈局的 Effects 觸發之前插入樣式
import { useInsertionEffect } from 'react';
// Inside your CSS-in-JS library
function useCSS(rule) {
useInsertionEffect(() => {
// ... inject <style> tags here ...
});
return rule;
}
參數
-
setup
:具有 Effect 邏輯的函式。您的 setup 函式也可以選擇性地返回一個*cleanup*函式。當您的元件被添加到 DOM 時,但在任何佈局 Effects 觸發之前,React 將運行您的 setup 函式。在每次重新渲染並更改 dependencies 後,React 將首先使用舊值運行 cleanup 函式(如果您提供的話),然後使用新值運行您的 setup 函式。當您的元件從 DOM 中移除時,React 將運行您的 cleanup 函式。 -
選用
dependencies
:在setup
程式碼內參考的所有反應值的列表。反應值包括 props、state,以及所有直接在元件主體內宣告的變數和函式。如果您的 linter 已針對 React 進行設定,它將驗證每個反應值是否已正確指定為 dependency。dependency 列表必須具有固定數量的項目,並且像[dep1, dep2, dep3]
一樣內嵌撰寫。React 將使用Object.is
比較演算法將每個 dependency 與其先前的值進行比較。如果您完全未指定 dependencies,則您的 Effect 將在每次元件重新渲染後重新執行。
回傳值
useInsertionEffect
返回 undefined
。
注意事項
- Effects 僅在客戶端上運行。它們在伺服器渲染期間不運行。
- 您無法在
useInsertionEffect
內部更新狀態。 - 當
useInsertionEffect
執行時,refs 還未附加。 useInsertionEffect
可能在 DOM 更新之前或之後執行。您不應該依賴 DOM 在任何特定時間點已更新。- 不同於其他類型的 Effects,它們會為每個 Effect 觸發清除,然後為每個 Effect 觸發設定,
useInsertionEffect
會一次一個組件地觸發清除和設定。這會導致清除和設定函式的「交錯」執行。
用法
從 CSS-in-JS 函式庫注入動態樣式
傳統上,您會使用純 CSS 來設定 React 組件的樣式。
// In your JS file:
<button className="success" />
// In your CSS file:
.success { color: green; }
有些團隊更喜歡直接在 JavaScript 程式碼中編寫樣式,而不是編寫 CSS 檔案。這通常需要使用 CSS-in-JS 函式庫或工具。CSS-in-JS 有三種常見的方法
- 使用編譯器靜態提取到 CSS 檔案
- 內聯樣式,例如
<div style={{ opacity: 1 }}>
- 在執行階段注入
<style>
標籤
如果您使用 CSS-in-JS,我們建議結合前兩種方法(CSS 檔案用於靜態樣式,內聯樣式用於動態樣式)。基於兩個原因,我們不建議在執行階段注入 <style>
標籤:
- 執行階段注入會迫使瀏覽器更頻繁地重新計算樣式。
- 如果在 React 生命週期的錯誤時間發生,執行階段注入可能會非常慢。
第一個問題無法解決,但 useInsertionEffect
可以幫助您解決第二個問題。
呼叫 useInsertionEffect
在任何佈局 Effects 觸發之前插入樣式
// Inside your CSS-in-JS library
let isInserted = new Set();
function useCSS(rule) {
useInsertionEffect(() => {
// As explained earlier, we don't recommend runtime injection of <style> tags.
// But if you have to do it, then it's important to do in useInsertionEffect.
if (!isInserted.has(rule)) {
isInserted.add(rule);
document.head.appendChild(getStyleForRule(rule));
}
});
return rule;
}
function Button() {
const className = useCSS('...');
return <div className={className} />;
}
與 useEffect
類似,useInsertionEffect
不會在伺服器上執行。如果您需要收集在伺服器上使用了哪些 CSS 規則,您可以在渲染期間執行此操作
let collectedRulesSet = new Set();
function useCSS(rule) {
if (typeof window === 'undefined') {
collectedRulesSet.add(rule);
}
useInsertionEffect(() => {
// ...
});
return rule;
}
閱讀更多關於使用執行階段注入將 CSS-in-JS 函式庫升級到 useInsertionEffect
的資訊。
深入探討
如果您在渲染期間插入樣式,而 React 正在處理 非阻塞更新,瀏覽器會在渲染組件樹時,每影格重新計算樣式,這可能會非常慢。
useInsertionEffect
比在 useLayoutEffect
或 useEffect
期間插入樣式更好,因為它可以確保在您的組件中執行其他 Effects 時,<style>
標籤已經插入。否則,由於樣式過時,一般 Effects 中的佈局計算會錯誤。