useTransition – React 中文文檔 | 您所在的位置:網(wǎng)站首頁 › 屬兔人2021年感情運勢怎么樣 › useTransition – React 中文文檔 |
useTransition 是一個幫助你在不阻塞 UI 的情況下更新狀態(tài)的 React Hook。 const [isPending, startTransition] = useTransition() 參考 useTransition() startTransition 函數(shù) 用法 將狀態(tài)更新標記為非阻塞的 transition 在 transition 中更新父組件 在 transition 期間顯示待處理的視覺狀態(tài) 避免不必要的加載指示器 構(gòu)建一個Suspense-enabled 的路由 Displaying an error to users with an error boundary Troubleshooting 在 transition 中無法更新輸入框內(nèi)容 React 沒有將狀態(tài)更新視為 transition 我想在組件外部調(diào)用 useTransition 我傳遞給 startTransition 的函數(shù)會立即執(zhí)行 參考 useTransition()在組件頂層調(diào)用 useTransition,將某些狀態(tài)更新標記為 transition。 import { useTransition } from 'react';function TabContainer() { const [isPending, startTransition] = useTransition(); // ……}參見下方更多示例。 參數(shù)useTransition 不需要任何參數(shù)。 返回值useTransition 返回一個由兩個元素組成的數(shù)組: isPending,告訴你是否存在待處理的 transition。 startTransition 函數(shù),你可以使用此方法將狀態(tài)更新標記為 transition。 startTransition 函數(shù)useTransition 返回的 startTransition 函數(shù)允許你將狀態(tài)更新標記為 transition。 function TabContainer() { const [isPending, startTransition] = useTransition(); const [tab, setTab] = useState('about'); function selectTab(nextTab) { startTransition(() => { setTab(nextTab); }); } // ……} 參數(shù) 作用域(scope):一個通過調(diào)用一個或多個 set 函數(shù) 更新狀態(tài)的函數(shù)。React 會立即不帶參數(shù)地調(diào)用此函數(shù),并將在 scope 調(diào)用期間將所有同步安排的狀態(tài)更新標記為 transition。它們將是非阻塞的,并且 不會顯示不想要的加載指示器。 返回值startTransition 不返回任何值。 注意useTransition 是一個 Hook,因此只能在組件或自定義 Hook 內(nèi)部調(diào)用。如果需要在其他地方啟動 transition(例如從數(shù)據(jù)庫),請調(diào)用獨立的 startTransition 函數(shù)。 只有在可以訪問該狀態(tài)的 set 函數(shù)時,才能將其對應的狀態(tài)更新包裝為 transition。如果你想啟用 transition 以響應某個 prop 或自定義 Hook 值,請嘗試使用 useDeferredValue。 傳遞給 startTransition 的函數(shù)必須是同步的。React 會立即執(zhí)行此函數(shù),并將在其執(zhí)行期間發(fā)生的所有狀態(tài)更新標記為 transition。如果在其執(zhí)行期間,嘗試稍后執(zhí)行狀態(tài)更新(例如在一個定時器中執(zhí)行狀態(tài)更新),這些狀態(tài)更新不會被標記為 transition。 標記為 transition 的狀態(tài)更新將被其他狀態(tài)更新打斷。例如在 transition 中更新圖表組件,并在圖表組件仍在重新渲染時繼續(xù)在輸入框中輸入,React 將首先處理輸入框的更新,之后再重新啟動對圖表組件的渲染工作。 transition 更新不能用于控制文本輸入。 目前,React 會批處理多個同時進行的 transition。這是一個限制,可能會在未來版本中刪除。 用法 將狀態(tài)更新標記為非阻塞的 transition在組件的頂層調(diào)用 useTransition 以將狀態(tài)更新標記為非阻塞的 transition。 import { useState, useTransition } from 'react';function TabContainer() { const [isPending, startTransition] = useTransition(); // ……}useTransition 返回一個由兩個元素組成的數(shù)組: isPending,告訴你是否存在待處理的 transition。 startTransition 函數(shù),你可以使用此方法將狀態(tài)更新標記為 transition。你可以按照以下方式將狀態(tài)更新標記為 transition: function TabContainer() { const [isPending, startTransition] = useTransition(); const [tab, setTab] = useState('about'); function selectTab(nextTab) { startTransition(() => { setTab(nextTab); }); } // ……}transition 可以使用戶界面的更新在慢速設備上仍保持響應性。 通過 transition,UI 仍將在重新渲染過程中保持響應性。例如用戶點擊一個選項卡,但改變了主意并點擊另一個選項卡,他們可以在不等待第一個重新渲染完成的情況下完成作。 使用 useTransition 與常規(guī)狀態(tài)更新的區(qū)別第 1 個示例 共 2 個挑戰(zhàn): 在 transition 中更新當前選項卡在此示例中,“文章”選項卡被 人為地減慢,以便至少需要一秒鐘才能渲染。 點擊“Posts”,然后立即點擊“Contact”。請注意,這會中斷“Posts”的緩慢渲染,而“聯(lián)系人”選項卡將會立即顯示。因為此狀態(tài)更新被標記為 transition,所以緩慢的重新渲染不會凍結(jié)用戶界面。 Forkimport { useState, useTransition } from 'react'; import TabButton from './TabButton.js'; import AboutTab from './AboutTab.js'; import PostsTab from './PostsTab.js'; import ContactTab from './ContactTab.js'; export default function TabContainer() { const [isPending, startTransition] = useTransition(); const [tab, setTab] = useState('about'); function selectTab(nextTab) { startTransition(() => { setTab(nextTab); }); } return ( selectTab('about')} > About selectTab('posts')} > Posts (slow) selectTab('contact')} > Contact {tab === 'about' && } {tab === 'posts' && } {tab === 'contact' && } ); } 在 transition 中更新父組件你也可以通過調(diào)用 useTransition 以更新父組件狀態(tài)。例如,TabButton 組件在 transition 中包裝了 onClick 邏輯: export default function TabButton({ children, isActive, onClick }) { const [isPending, startTransition] = useTransition(); if (isActive) { return {children} } return ( { startTransition(() => { onClick(); }); }}> {children} );}由于父組件的狀態(tài)更新在 onClick 事件處理程序內(nèi),所以該狀態(tài)更新會被標記為 transition。這就是為什么可以在點擊“Posts”后立即點擊“Contact”。由于更新選定選項卡被標記為了 transition,因此它不會阻止用戶交互。 Forkimport { useTransition } from 'react'; export default function TabButton({ children, isActive, onClick }) { const [isPending, startTransition] = useTransition(); if (isActive) { return {children} } return ( { startTransition(() => { onClick(); }); }}> {children} ); } 在 transition 期間顯示待處理的視覺狀態(tài)你可以使用 useTransition 返回的 isPending 布爾值來向用戶表明當前處于 transition 中。例如,選項卡按鈕可以有一個特殊的“pending”視覺狀態(tài): function TabButton({ children, isActive, onClick }) { const [isPending, startTransition] = useTransition(); // ... if (isPending) { return {children}; } // ...請注意,現(xiàn)在點擊“Posts”感覺更加靈敏,因為選項卡按鈕本身立即更新了: Forkimport { useTransition } from 'react'; export default function TabButton({ children, isActive, onClick }) { const [isPending, startTransition] = useTransition(); if (isActive) { return {children} } if (isPending) { return {children}; } return ( { startTransition(() => { onClick(); }); }}> {children} ); } 避免不必要的加載指示器在這個例子中,PostsTab 組件從啟用了 Suspense 的數(shù)據(jù)源中獲取了一些數(shù)據(jù)。當你點擊“Posts”選項卡時,PostsTab 組件將 掛起,導致最近的加載中的后備方案出現(xiàn): Forkimport { Suspense, useState } from 'react'; import TabButton from './TabButton.js'; import AboutTab from './AboutTab.js'; import PostsTab from './PostsTab.js'; import ContactTab from './ContactTab.js'; export default function TabContainer() { const [tab, setTab] = useState('about'); return ( setTab('about')} > About setTab('posts')} > Posts setTab('contact')} > Contact {tab === 'about' && } {tab === 'posts' && } {tab === 'contact' && } ); }隱藏整個選項卡容器以顯示加載指示符會導致用戶體驗不連貫。如果你將 useTransition 添加到 TabButton 中,你可以改為在選項卡按鈕中指示待處理狀態(tài)。 請注意,現(xiàn)在點擊“帖子”不再用一個旋轉(zhuǎn)器替換整個選項卡容器: Forkimport { useTransition } from 'react'; export default function TabButton({ children, isActive, onClick }) { const [isPending, startTransition] = useTransition(); if (isActive) { return {children} } if (isPending) { return {children}; } return ( { startTransition(() => { onClick(); }); }}> {children} ); }了解有關(guān)在Suspense中使用轉(zhuǎn)換的更多信息。 注意轉(zhuǎn)換效果只會“等待”足夠長的時間來避免隱藏 已經(jīng)顯示 的內(nèi)容(例如選項卡容器)。如果“帖子”選項卡具有一個嵌套 邊界,轉(zhuǎn)換效果將不會“等待”它。 構(gòu)建一個Suspense-enabled 的路由如果你正在構(gòu)建一個 React 框架或路由,我們建議將頁面導航標記為轉(zhuǎn)換效果。 function Router() { const [page, setPage] = useState('/'); const [isPending, startTransition] = useTransition(); function navigate(url) { startTransition(() => { setPage(url); }); } // ...這么做有兩個好處: 轉(zhuǎn)換效果是可中斷的,這樣用戶可以在等待重新渲染完成之前點擊其他地方。 轉(zhuǎn)換效果可以防止不必要的加載指示符,這樣用戶就可以避免在導航時產(chǎn)生不協(xié)調(diào)的跳轉(zhuǎn)。下面是一個簡單的使用轉(zhuǎn)換效果進行頁面導航的路由器示例: Forkimport { Suspense, useState, useTransition } from 'react'; import IndexPage from './IndexPage.js'; import ArtistPage from './ArtistPage.js'; import Layout from './Layout.js'; export default function App() { return ( ); } function Router() { const [page, setPage] = useState('/'); const [isPending, startTransition] = useTransition(); function navigate(url) { startTransition(() => { setPage(url); }); } let content; if (page === '/') { content = ( ); } else if (page === '/the-beatles') { content = ( ); } return ( {content} ); } function BigSpinner() { return ?? Loading...; } 注意啟用 Suspense 的路由默認情況下會將頁面導航更新包裝為 transition。 Displaying an error to users with an error boundary CanaryError Boundary for useTransition is currently only available in React’s canary and experimental channels. Learn more about React’s release channels here. If a function passed to startTransition throws an error, you can display an error to your user with an error boundary. To use an error boundary, wrap the component where you are calling the useTransition in an error boundary. Once the function passed to startTransition errors, the fallback for the error boundary will be displayed. Forkimport { useTransition } from "react"; import { ErrorBoundary } from "react-error-boundary"; export function AddCommentContainer() { return ( ); } function addComment(comment) { // For demonstration purposes to show Error Boundary if (comment == null) { throw new Error("Example Error: An error thrown to trigger error boundary"); } } function AddCommentButton() { const [pending, startTransition] = useTransition(); return ( { startTransition(() => { // Intentionally not passing a comment // so error gets thrown addComment(); }); }} > Add comment ); } Troubleshooting 在 transition 中無法更新輸入框內(nèi)容不應將控制輸入框的狀態(tài)變量標記為 transition: const [text, setText] = useState('');// ..ction handleChange(e) { // ? 不應將受控輸入框的狀態(tài)變量標記為 transition startTransition(() => { setText(e.target.value); });}// ...return ;這是因為 transition 是非阻塞的,但是在響應更改事件時更新輸入應該是同步的。如果想在輸入時運行一個 transition,那么有兩種做法: 聲明兩個獨立的狀態(tài)變量:一個用于輸入狀態(tài)(它總是同步更新),另一個用于在 transition 中更新。這樣,便可以使用同步狀態(tài)控制輸入,并將用于 transition 的狀態(tài)變量(它將“滯后”于輸入)傳遞給其余的渲染邏輯。 或者使用一個狀態(tài)變量,并添加 useDeferredValue,它將“滯后”于實際值,并自動觸發(fā)非阻塞的重新渲染以“追趕”新值。 React 沒有將狀態(tài)更新視為 transition當在 transition 中包裝狀態(tài)更新時,請確保它發(fā)生在 startTransition 調(diào)用期間: startTransition(() => { // ? 在調(diào)用 startTransition 中更新狀態(tài) setPage('/about');});傳遞給 startTransition 的函數(shù)必須是同步的。 你不能像這樣將更新標記為 transition: startTransition(() => { // ? 在調(diào)用 startTransition 后更新狀態(tài) setTimeout(() => { setPage('/about'); }, 1000);});相反,你可以這樣做: setTimeout(() => { startTransition(() => { // ? 在調(diào)用 startTransition 中更新狀態(tài) setPage('/about'); });}, 1000);類似地,你不能像這樣將更新標記為 transition: startTransition(async () => { await someAsyncFunction(); // ? 在調(diào)用 startTransition 后更新狀態(tài) setPage('/about');});然而,使用以下方法可以正常工作: await someAsyncFunction();startTransition(() => { // ? 在調(diào)用 startTransition 中更新狀態(tài) setPage('/about');}); 我想在組件外部調(diào)用 useTransitionuseTransition 是一個 Hook,因此不能在組件外部調(diào)用。請使用獨立的 startTransition 方法。它們的工作方式相同,但不提供 isPending 標記。 我傳遞給 startTransition 的函數(shù)會立即執(zhí)行如果你運行這段代碼,它將會打印 1, 2, 3: console.log(1);startTransition(() => { console.log(2); setPage('/about');});console.log(3);期望打印 1, 2, 3。傳遞給 startTransition 的函數(shù)不會被延遲執(zhí)行。與瀏覽器的 setTimeout 不同,它不會延遲執(zhí)行回調(diào)。React 會立即執(zhí)行你的函數(shù),但是在它運行的同時安排的任何狀態(tài)更新都被標記為 transition。你可以將其想象為以下方式: // React 運行的簡易版本let isInsideTransition = false;function startTransition(scope) { isInsideTransition = true; scope(); isInsideTransition = false;}function setState() { if (isInsideTransition) { // ……安排 transition 狀態(tài)更新…… } else { // ……安排緊急狀態(tài)更新…… }} |
今日新聞 |
推薦新聞 |
專題文章 |
CopyRight 2018-2019 實驗室設備網(wǎng) 版權(quán)所有 |