React官網Hook學習——下篇
本文記錄的是React官網部分的內置Hook學習第二部分
10、useInsertionEffect
useInsertionEffect 可以在佈局副作用觸發之前將元素插入到 DOM 中。
useInsertionEffect(setup, dependencies?)
11、useLayoutEffect
useLayoutEffect可能會影響性能。儘可能使用 useEffect。
useLayoutEffect 是 useEffect 的一個版本,在瀏覽器重新繪製屏幕之前觸發。
useLayoutEffect(setup, dependencies?)
參考
useLayoutEffect(setup, dependencies?)
調用 useLayoutEffect 在瀏覽器重新繪製屏幕之前進行佈局測量:
import { useState, useRef, useLayoutEffect } from 'react';
function Tooltip() {
const ref = useRef(null);
const [tooltipHeight, setTooltipHeight] = useState(0);
useLayoutEffect(() => {
const { height } = ref.current.getBoundingClientRect();
setTooltipHeight(height);
}, []);
// ...
參數
setup:處理副作用的函數。setup 函數選擇性返回一個清理(cleanup)函數。在將組件首次添加到 DOM 之前,React 將運行 setup 函數。在每次因為依賴項變更而重新渲染後,React 將首先使用舊值運行 cleanup 函數(如果你提供了該函數),然後使用新值運行 setup 函數。在組件從 DOM 中移除之前,React 將最後一次運行 cleanup 函數。- 可選
dependencies:setup代碼中引用的所有響應式值的列表。響應式值包括 props、state 以及所有直接在組件內部聲明的變量和函數。如果你的代碼檢查工具 配置了 React,那麼它將驗證每個響應式值都被正確地指定為一個依賴項。依賴項列表必須具有固定數量的項,並且必須像[dep1, dep2, dep3]這樣內聯編寫。React 將使用 Object.is 來比較每個依賴項和它先前的值。如果省略此參數,則在每次重新渲染組件之後,將重新運行副作用函數。
返回值
useLayoutEffect 返回 undefined。
注意事項
useLayoutEffect是一個 Hook,因此只能在 組件的頂層 或自己的 Hook 中調用它。不能在循環或者條件內部調用它。如果你需要的話,抽離出一個組件並將副作用處理移動到那裏。- 當 StrictMode 啓用時,React 將在真正的 setup 函數首次運行前,運行一個額外的開發專有的 setup + cleanup 週期。這是一個壓力測試,確保 cleanup 邏輯“映照”到 setup 邏輯,並停止或撤消 setup 函數正在做的任何事情。如果這導致一個問題,請實現清理函數。
- 如果你的一些依賴項是組件內部定義的對象或函數,則存在這樣的風險,即它們將 導致 Effect 重新運行的次數多於所需的次數。要解決這個問題,請刪除不必要的 對象 和 函數 依賴項。你還可以 抽離狀態更新 和 非響應式邏輯 到 Effect 之外。
- Effect 只在客户端上運行,在服務端渲染中不會運行。
useLayoutEffect內部的代碼和所有計劃的狀態更新阻塞了瀏覽器重新繪製屏幕。如果過度使用,這會使你的應用程序變慢。如果可能的話,儘量選擇 useEffect。- 如果你在
useLayoutEffect內部觸發狀態更新,React 將立即執行所有剩餘的 Effects,包括useEffect。
用法
在瀏覽器重新繪製屏幕前計算佈局
大多數組件不需要依靠它們在屏幕上的位置和大小來決定渲染什麼。他們只返回一些 JSX,然後瀏覽器計算他們的 佈局(位置和大小)並重新繪製屏幕。
有時候,這還不夠。想象一下懸停時出現在某個元素旁邊的 tooltip。如果有足夠的空間,tooltip 應該出現在元素的上方,但是如果不合適,它應該出現在下面。為了讓 tooltip 渲染在最終正確的位置,你需要知道它的高度(即它是否適合放在頂部)。
要做到這一點,你需要分兩步渲染:
- 將 tooltip 渲染到任何地方(即使位置不對)。
- 測量它的高度並決定放置 tooltip 的位置。
- 把 tooltip 渲染放在正確的位置。
所有這些都需要在瀏覽器重新繪製屏幕之前完成。你不希望用户看到 tooltip 在移動。
下面是這如何一步步工作的:
Tooltip使用初始值tooltipHeight = 0進行渲染(因此 tooltip 可能被錯誤地放置)。- React 將它放在 DOM 中,然後運行
useLayoutEffect中的代碼。 useLayoutEffect測量 了 tooltip 內容的高度,並立即觸發重新渲染。- 使用實際的
tooltipHeight再次渲染Tooltip(這樣 tooltip 的位置就正確了)。 - React 在 DOM 中對它進行更新,瀏覽器最終顯示出 tooltip。
將鼠標懸停在下面的按鈕上,看看 tooltip 是如何根據它是否合適來調整它的位置:
import { useRef, useLayoutEffect, useState } from 'react';
import { createPortal } from 'react-dom';
import TooltipContainer from './TooltipContainer.js';
export default function Tooltip({ children, targetRect }) {
const ref = useRef(null);
const [tooltipHeight, setTooltipHeight] = useState(0);
useLayoutEffect(() => {
const { height } = ref.current.getBoundingClientRect();
setTooltipHeight(height);
console.log('Measured tooltip height: ' + height);
}, []);
let tooltipX = 0;
let tooltipY = 0;
if (targetRect !== null) {
tooltipX = targetRect.left;
tooltipY = targetRect.top - tooltipHeight;
if (tooltipY < 0) {
// 它不適合上方,因此把它放在下面。
tooltipY = targetRect.bottom;
}
}
return createPortal(
<TooltipContainer x={tooltipX} y={tooltipY} contentRef={ref}>
{children}
</TooltipContainer>,
document.body
);
}
12、useMemo
useMemo 是一個 React Hook,它在每次重新渲染的時候能夠緩存計算的結果。
const cachedValue = useMemo(calculateValue, dependencies)
參考
useMemo(calculateValue, dependencies)
在組件的頂層調用 useMemo 來緩存每次重新渲染都需要計算的結果。
import { useMemo } from 'react';
function TodoList({ todos, tab }) {
const visibleTodos = useMemo(
() => filterTodos(todos, tab),
[todos, tab]
);
// ...
}
參數
calculateValue:要緩存計算值的函數。它應該是一個沒有任何參數的純函數,並且可以返回任意類型。React 將會在首次渲染時調用該函數;在之後的渲染中,如果dependencies沒有發生變化,React 將直接返回相同值。否則,將會再次調用calculateValue並返回最新結果,然後緩存該結果以便下次重複使用。dependencies:所有在calculateValue函數中使用的響應式變量組成的數組。響應式變量包括 props、state 和所有你直接在組件中定義的變量和函數。如果你在代碼檢查工具中 配置了 React,它將會確保每一個響應式數據都被正確地定義為依賴項。依賴項數組的長度必須是固定的並且必須寫成[dep1, dep2, dep3]這種形式。React 使用 Object.is 將每個依賴項與其之前的值進行比較。
返回值
在初次渲染時,useMemo 返回不帶參數調用 calculateValue 的結果。
在接下來的渲染中,如果依賴項沒有發生改變,它將返回上次緩存的值;否則將再次調用 calculateValue,並返回最新結果。
注意
useMemo是一個 React Hook,所以你只能 在組件的頂層 或者自定義 Hook 中調用它。你不能在循環語句或條件語句中調用它。如有需要,將其提取為一個新組件並使用 state。- 在嚴格模式下,為了 幫你發現意外的錯誤,React 將會 調用你的計算函數兩次。這只是一個開發環境下的行為,並不會影響到生產環境。如果計算函數是一個純函數(它本來就應該是),這將不會影響到代碼邏輯。其中一次的調用結果將被忽略。
- 除非有特定原因,React 不會丟棄緩存值。例如,在開發過程中,React 會在你編輯組件文件時丟棄緩存。無論是在開發環境還是在生產環境,如果你的組件在初始掛載期間被終止,React 都會丟棄緩存。在未來,React 可能會添加更多利用丟棄緩存的特性——例如,如果 React 在未來增加了對虛擬化列表的內置支持,那麼丟棄那些滾出虛擬化列表視口的緩存是有意義的。你可以僅僅依賴
useMemo作為性能優化手段。否則,使用 state 變量 或者 ref 可能更加合適。
13、useOptimistic
useOptimistic 是一個 React Hook,它可以幫助你更樂觀地更新用户界面。
const [optimisticState, addOptimistic] = useOptimistic(state, updateFn);
參考
useOptimistic(state, updateFn)
useOptimistic 是一個 React Hook,它允許你在進行異步操作時顯示不同 state。它接受 state 作為參數,並返回該 state 的副本,在異步操作(如網絡請求)期間可以不同。你需要提供一個函數,該函數接受當前 state 和操作的輸入,並返回在操作掛起期間要使用的樂觀狀態。
這個狀態被稱為“樂觀”狀態是因為通常用於立即向用户呈現執行操作的結果,即使實際上操作需要一些時間來完成。
import { useOptimistic } from 'react';
function AppContainer() {
const [optimisticState, addOptimistic] = useOptimistic(
state,
// 更新函數
(currentState, optimisticValue) => {
// 使用樂觀值
// 合併並返回新 state
}
);
}
參數
state:初始時和沒有掛起操作時要返回的值。updateFn(currentState, optimisticValue):一個函數,接受當前 state 和傳遞給addOptimistic的樂觀值,並返回結果樂觀狀態。它必須是一個純函數。updateFn接受兩個參數:currentState和optimisticValue。返回值將是currentState和optimisticValue的合併值。
返回值
optimisticState:結果樂觀狀態。除非有操作掛起,否則它等於state,在這種情況下,它等於updateFn返回的值。addOptimistic:觸發樂觀更新時調用的 dispatch 函數。它接受一個可以是任何類型的參數optimisticValue,並以state和optimisticValue作為參數來調用updateFn。
用法
樂觀地更新表單
seOptimistic Hook 提供了一種在後台操作(如網絡請求)完成之前樂觀地更新用户界面的方式。在表單的上下文中,這種技術有助於使應用程序在感覺上響應地更加快速。當用户提交表單時,界面立即更新為預期的結果,而不是等待服務器的響應來反映更改。
import { useOptimistic, useState, useRef, startTransition } from "react";
import { deliverMessage } from "./actions.js";
function Thread({ messages, sendMessageAction }) {
const formRef = useRef();
function formAction(formData) {
addOptimisticMessage(formData.get("message"));
formRef.current.reset();
startTransition(async () => {
await sendMessageAction(formData);
});
}
const [optimisticMessages, addOptimisticMessage] = useOptimistic(
messages,
(state, newMessage) => [
{
text: newMessage,
sending: true
},
...state,
]
);
return (
<>
<form action={formAction} ref={formRef}>
<input type="text" name="message" placeholder="你好!" />
<button type="submit">發送</button>
</form>
{optimisticMessages.map((message, index) => (
<div key={index}>
{message.text}
{!!message.sending && <small>(發送中……)</small>}
</div>
))}
</>
);
}
export default function App() {
const [messages, setMessages] = useState([
{ text: "你好,在這兒!", sending: false, key: 1 }
]);
async function sendMessageAction(formData) {
const sentMessage = await deliverMessage(formData.get("message"));
startTransition(() => {
setMessages((messages) => [{ text: sentMessage }, ...messages]);
})
}
return <Thread messages={messages} sendMessageAction={sendMessageAction} />;
}
export async function deliverMessage(message) {
await new Promise((res) => setTimeout(res, 1000));
return message;
}
14、useReducer
useReducer 是一個 React Hook,它允許你向組件裏面添加一個 reducer。
const [state, dispatch] = useReducer(reducer, initialArg, init?)
參考
useReducer(reducer, initialArg, init?)
在組件的頂層作用域調用 useReducer 以創建一個用於管理狀態的 reducer。
import { useReducer } from 'react';
function reducer(state, action) {
// ...
}
function MyComponent() {
const [state, dispatch] = useReducer(reducer, { age: 42 });
// ...
參數
reducer:用於更新 state 的純函數。參數為 state 和 action,返回值是更新後的 state。state 與 action 可以是任意合法值。initialArg:用於初始化 state 的任意值。初始值的計算邏輯取決於接下來的init參數。- 可選參數
init:用於計算初始值的函數。如果存在,使用init(initialArg)的執行結果作為初始值,否則使用initialArg。
返回值
useReducer 返回一個由兩個值組成的數組:
- 當前的 state。初次渲染時,它是
init(initialArg)或initialArg(如果沒有init函數)。 - dispatch。用於更新 state 並觸發組件的重新渲染。
注意事項
useReducer是一個 Hook,所以只能在 組件的頂層作用域 或自定義 Hook 中調用,而不能在循環或條件語句中調用。如果你有這種需求,可以創建一個新的組件,並把 state 移入其中。dispatch函數具有穩定的標識,所以你經常會看到 Effect 的依賴數組中會省略它,即使包含它也不會導致 Effect 重新觸發。如果 linter 允許你省略依賴項並且沒有報錯,那麼你就可以安全地省略它。瞭解移除 Effect 依賴項的更多信息。- 嚴格模式下 React 會 調用兩次 reducer 和初始化函數,這可以 幫助你發現意外的副作用。這只是開發模式下的行為,並不會影響生產環境。只要 reducer 和初始化函數是純函數(理應如此)就不會改變你的邏輯。其中一個調用結果會被忽略。
dispatch 函數
useReducer 返回的 dispatch 函數允許你更新 state 並觸發組件的重新渲染。它需要傳入一個 action 作為參數:
const [state, dispatch] = useReducer(reducer, { age: 42 });
function handleClick() {
dispatch({ type: 'incremented_age' });
// ...
React 會調用 reducer 函數以更新 state,reducer 函數的參數為當前的 state 與傳遞的 action。
參數
action:用户執行的操作。可以是任意類型的值。通常來説 action 是一個對象,其中type屬性標識類型,其它屬性攜帶額外信息。
返回值
dispatch 函數沒有返回值。
注意
dispatch函數 是為下一次渲染而更新 state。因此在調用dispatch函數後讀取 state 並不會拿到更新後的值,也就是説只能獲取到調用前的值。- 如果你提供的新值與當前的
state相同(使用 Object.is 比較),React 會 跳過組件和子組件的重新渲染,這是一種優化手段。雖然在跳過重新渲染前 React 可能會調用你的組件,但是這不應該影響你的代碼。 - React 會批量更新 state。state 會在 所有事件函數執行完畢 並且已經調用過它的
set函數後進行更新,這可以防止在一個事件中多次進行重新渲染。如果在訪問 DOM 等極少數情況下需要強制 React 提前更新,可以使用 flushSync。
15、useRef
useRef 是一個 React Hook,它能幫助引用一個不需要渲染的值。
const ref = useRef(initialValue)
參考
useRef(initialValue)
在組件頂層調用 useRef 以聲明一個 ref。
import { useRef } from 'react';
function MyComponent() {
const intervalRef = useRef(0);
const inputRef = useRef(null);
// ...
參數
initialValue:ref 對象的current屬性的初始值。可以是任意類型的值。這個參數在首次渲染後被忽略。
返回值
useRef 返回一個只有一個屬性的對象:
current:初始值為傳遞的initialValue。之後可以將其設置為其他值。如果將 ref 對象作為一個 JSX 節點的ref屬性傳遞給 React,React 將為它設置current屬性。
在後續的渲染中,useRef 將返回同一個對象。
注意
- 可以修改
ref.current屬性。與 state 不同,它是可變的。然而,如果它持有一個用於渲染的對象(例如 state 的一部分),那麼就不應該修改這個對象。 - 改變
ref.current屬性時,React 不會重新渲染組件。React 不知道它何時會發生改變,因為 ref 是一個普通的 JavaScript 對象。 - 除了 初始化 外不要在渲染期間寫入或者讀取
ref.current,否則會使組件行為變得不可預測。 - 在嚴格模式下,React 將會 調用兩次組件方法,這是為了 幫助發現意外問題。但這只是開發模式下的行為,不會影響生產模式。每個 ref 對象都將會創建兩次,但是其中一個版本將被丟棄。如果使用的是組件純函數(也應當如此),那麼這不會影響其行為。
16、useState
useState 是一個 React Hook,它允許你向組件添加一個 狀態變量。
const [state, setState] = useState(initialState)
參考
useState(initialState)
在組件的頂層調用 useState 來聲明一個 狀態變量。
import { useState } from 'react';
function MyComponent() {
const [age, setAge] = useState(28);
const [name, setName] = useState('Taylor');
const [todos, setTodos] = useState(() => createTodos());
// ...
按照慣例使用 數組解構 來命名狀態變量,例如 [something, setSomething]。
參數
- initialState:你希望 state 初始化的值。它可以是任何類型的值,但對於函數有特殊的行為。在初始渲染後,此參數將被忽略。
- 如果傳遞函數作為
initialState,則它將被視為 初始化函數。它應該是純函數,不應該接受任何參數,並且應該返回一個任何類型的值。當初始化組件時,React 將調用你的初始化函數,並將其返回值存儲為初始狀態。
返回
useState 返回一個由兩個值組成的數組:
- 當前的 state。在首次渲染時,它將與你傳遞的
initialState相匹配。 - set,它可以讓你將 state 更新為不同的值並觸發重新渲染。
注意事項
useState是一個 Hook,因此你只能在 組件的頂層 或自己的 Hook 中調用它。你不能在循環或條件語句中調用它。如果你需要這樣做,請提取一個新組件並將狀態移入其中。- 在嚴格模式中,React 將 兩次調用初始化函數,以 幫你找到意外的不純性。這只是開發時的行為,不影響生產。如果你的初始化函數是純函數(本該是這樣),就不應影響該行為。其中一個調用的結果將被忽略。
set 函數,例如 setSomething(nextState)
useState 返回的 set 函數允許你將 state 更新為不同的值並觸發重新渲染。你可以直接傳遞新狀態,也可以傳遞一個根據先前狀態來計算新狀態的函數:
const [name, setName] = useState('Edward');
function handleClick() {
setName('Taylor');
setAge(a => a + 1);
// ...
參數
- nextState:你想要 state 更新為的值。它可以是任何類型的值,但對於函數有特殊的行為。
- 如果你將函數作為
nextState傳遞,它將被視為 更新函數。它必須是純函數,只接受待定的 state 作為其唯一參數,並應返回下一個狀態。React 將把你的更新函數放入隊列中並重新渲染組件。在下一次渲染期間,React 將通過把隊列中所有更新函數應用於先前的狀態來計算下一個狀態。
返回值
set 函數沒有返回值。
注意事項
set函數 僅更新 *下一次* 渲染的狀態變量。如果在調用set函數後讀取狀態變量,則 仍會得到在調用之前顯示在屏幕上的舊值。- 如果你提供的新值與當前
state相同(由 Object.is 比較確定),React 將 跳過重新渲染該組件及其子組件。這是一種優化。雖然在某些情況下 React 仍然需要在跳過子組件之前調用你的組件,但這不應影響你的代碼。 - React 會 批量處理狀態更新。它會在所有 事件處理函數運行 並調用其
set函數後更新屏幕。這可以防止在單個事件期間多次重新渲染。在某些罕見情況下,你需要強制 React 更早地更新屏幕,例如訪問 DOM,你可以使用 flushSync。 set函數具有穩定的標識,所以你經常會看到 Effect 的依賴數組中會省略它,即使包含它也不會導致 Effect 重新觸發。如果 linter 允許你省略依賴項並且沒有報錯,那麼你就可以安全地省略它。瞭解移除 Effect 依賴項的更多信息。- 在渲染期間,只允許在當前渲染組件內部調用
set函數。React 將丟棄其輸出並立即嘗試使用新狀態重新渲染。這種方式很少需要,但你可以使用它來存儲 先前渲染中的信息。 - 在嚴格模式中,React 將 兩次調用你的更新函數,以幫助你找到 意外的不純性。這只是開發時的行為,不影響生產。如果你的更新函數是純函數(本該是這樣),就不應影響該行為。其中一次調用的結果將被忽略。
17、useSyncExternalStore
useSyncExternalStore 是一個讓你訂閲外部 store 的 React Hook。
const snapshot = useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot?)
參考
useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot?)
在組件頂層調用 useSyncExternalStore 以從外部 store 讀取值。
import { useSyncExternalStore } from 'react';
import { todosStore } from './todoStore.js';
function TodosApp() {
const todos = useSyncExternalStore(todosStore.subscribe, todosStore.getSnapshot);
// ...
}
它返回 store 中數據的快照。你需要傳兩個函數作為參數:
subscribe函數應當訂閲該 store 並返回一個取消訂閲的函數。getSnapshot函數應當從該 store 讀取數據的快照。
參數
subscribe:一個函數,接收一個單獨的callback參數並把它訂閲到 store 上。當 store 發生改變時應該調用提供的callback,這將使 React 重新調用getSnapshot並在需要的時候重新渲染組件。subscribe函數會返回清除訂閲的函數。getSnapshot:一個函數,返回組件需要的 store 中的數據快照。在 store 不變的情況下,重複調用getSnapshot必須返回同一個值。如果 store 改變,並且返回值也不同了(用 Object.is 比較),React 就會重新渲染組件。- 可選
getServerSnapshot:一個函數,返回 store 中數據的初始快照。它只會在服務端渲染時,以及在客户端進行服務端渲染內容的激活時被用到。快照在服務端與客户端之間必須相同,它通常是從服務端序列化並傳到客户端的。如果你忽略此參數,在服務端渲染這個組件會拋出一個錯誤。
返回值
該 store 的當前快照,可以在你的渲染邏輯中使用。
警告
getSnapshot返回的 store 快照必須是不可變的。如果底層 store 有可變數據,要在數據改變時返回一個新的不可變快照。否則,返回上次緩存的快照。- 如果在重新渲染時傳入一個不同的
subscribe函數,React 會用新傳入的subscribe函數重新訂閲該 store。你可以通過在組件外聲明subscribe來避免。 - 如果在 非阻塞 Transition 更新 過程中更改了 store,React 將會回退並將該更新視為阻塞更新。具體來説,在每次 Transition 更新時,React 將在將更改應用到 DOM 之前第二次調用
getSnapshot。如果它返回的值與最初調用時不同,React 將重新從頭開始進行更新,這次將其作為阻塞更新應用,以確保屏幕上的每個組件都反映 store 的相同版本。 - 不建議根據
useSyncExternalStore返回的 store 值暫停渲染。原因是對外部 store 的變更無法 被標記為非阻塞 Transition 更新,因此它們會觸發最近的 Suspense,用加載旋轉器替換已經呈現在屏幕上的內容,通常會導致較差的用户體驗。
18、useTransition
useTransition 是一個讓你可以在後台渲染部分 UI 的 React Hook。
const [isPending, startTransition] = useTransition()
參考
useTransition()
在組件頂層調用 useTransition,將某些狀態更新標記為 transition。
import { useTransition } from 'react';
function TabContainer() {
const [isPending, startTransition] = useTransition();
// ……
}
參數
useTransition 不需要任何參數。
返回值
useTransition 返回一個由兩個元素組成的數組:
isPending,告訴你是否存在待處理的 transition。- startTransition,你可以使用此方法將更新標記為 transition。
startTransition 函數
useTransition 返回的 startTransition 函數允許你將更新標記為 Transition。
參數
action:通過調用一個或多個 set 來更新某些狀態的函數。React 會立即調用action(無需參數),並將action函數調用期間同步調度的所有狀態更新標記為 Transition。在action中通過await等待的異步調用會被包含在 Transition 中,但目前需要在await之後將任何set函數再次包裹在startTransition中(參見疑難解答)。標記為 Transition 的狀態更新將具備非阻塞特性,並且不會顯示不必要的加載指示。
返回值
startTransition 不返回任何值。
注意
useTransition是一個 Hook,因此只能在組件或自定義 Hook 內部調用。如果需要在其他地方啓動 transition(例如從數據庫),請調用獨立的 startTransition 函數。- 只有在可以訪問該狀態的
set函數時,才能將其對應的狀態更新包裝為 transition。如果你想啓用 Transition 以響應某個 prop 或自定義 Hook 值,請嘗試使用 useDeferredValue。 - 傳遞給
startTransition的函數會被立即執行,並將在其執行期間發生的所有狀態更新標記為 transition。如果你嘗試在setTimeout中執行狀態更新,它們將不會被標記為 transition。 - 你必須將任意異步請求之後的狀態更新用
startTransition包裹,以將其標記為 Transition 更新。這是一個已知限制,我們將在未來版本中修復(參見疑難解答)。 startTransition函數具有穩定的標識,所以你經常會看到 Effect 的依賴數組中會省略它,即使包含它也不會導致 Effect 重新觸發。如果 linter 允許你省略依賴項並且沒有報錯,那麼你就可以安全地省略它。- 標記為 Transition 的狀態更新將被其他狀態更新打斷。例如在 Transition 中更新圖表組件,並在圖表組件仍在重新渲染時繼續在輸入框中輸入,React 將首先處理輸入框的更新,之後再重新啓動對圖表組件的渲染工作。
- Transition 更新不能用於控制文本輸入。
- 目前,React 會批處理多個同時進行的 transition。這是一個限制,可能會在未來版本中刪除。