useTransition基礎用法
給別人的github庫提的pr,他寫的關於其他hook的使用也很清晰易懂
useTransition概念介紹
react提供了useDeferredValue
發揮類似防抖節流的作用,而useTransition
也是類似的作用,但是該hook是透過降低資料渲染的優先順序來達到優先更新其他資料
useTransition用來解決什麼問題?
- 首先給定一個場景,開發時經常會遇到需要聯想輸入,也就是輸入的同時要返回聯想搜尋結果的列表。
- 但是這個列表有時返回值非常的長,有時會導致使用者輸入值的更新緩慢,這裡就產生了一個問題,當頁面有大量UI更新的時候,怎麼處理資料更新不會卡頓。
- 可以手寫防抖節流,防抖有一個弊端,當我們長時間的持續輸入(時間間隔小於防抖設定的時間),頁面就會長時間都不到響應。而startTransition 可以指定 UI 的渲染優先順序,哪些需要實時更新,哪些需要延遲更新。即使使用者長時間輸入最遲 5s 也會更新一次。
- 也可以用
useDeferredValue
,也可以用“可視視窗載入”的方案,
在這裡介紹怎麼用useTransition
解決
useTransition原始碼
回到useTransition的學習中,首先看一下React原始碼中的ReactHooks.js。
export function useTransition(): [
boolean,
(callback: () => void, options?: StartTransitionOptions) => void,
] {
const dispatcher = resolveDispatcher();
return dispatcher.useTransition();
}
再根據引入檔案,到react-reconciler/src/ReactInternalTypes.js
找到Dispatch裡最終呼叫的useTransition
useTransition(): [
boolean,
(callback: () => void, options?: StartTransitionOptions) => void,
],
上述程式碼看不懂沒關係,本系列教程只是講述“如何使用Hook”,並不是“Hook原始碼分析”。^_^
useTransition基本用法
useTransition()函式可以不傳參,傳參可以傳一個毫秒值用來修改最遲更新時間,startTransition回撥裡的賦值將會被降低優先順序。isPending 指示過渡任務何時活躍以顯示一個等待狀態。
程式碼形式
const [isPending, startTransition] = useTransition();
startTransition(() => {
setCount(count + 1);
})
傳參寫法
// 延遲兩秒
const [isPending, startTransition] = useTransition(2000);
startTransition(() => {
setCount(count + 1);
})
useTransition使用示例
舉例:搜尋引擎的關鍵詞聯想。一般來說,對於使用者在輸入框中輸入都希望是實時更新的,如果此時聯想詞比較多同時也要實時更新的話,這就可能會導致使用者的輸入會卡頓。這樣一來使用者的體驗會變差,這並不是我們想要的結果。
我們將這個場景的狀態更新提取出來:一個是使用者輸入的更新;一個是聯想詞的更新,這個兩個更新緊急程度顯然前者大於後者。
這裡更新效果可能還不夠明顯,可以開啟瀏覽器控制檯,點選performance insights
項,在Measure page load右邊有個下拉選項,在cpu那欄的右邊下拉選擇4x slowdown
可以將瀏覽器執行速度調慢四倍,這樣卡頓會明顯些。
這裡拆分為兩個元件,父元件是useTransition的使用,子元件是列表渲染,程式碼如下:
父元件:
import { useState, useTransition } from 'react'
import ProductList from './components/ProductList'
// 列表資料的生成
export function generateProducts() {
const products: Array<string> = []
for (let i = 0; i < 10000; i++) {
products.push(`Product ${i + 1}`)
}
return products
}
// 列表資料
const dummyProducts = generateProducts()
// 使用者輸入時過濾搜尋,達到一個聯想輸入的效果
function filterProducts(filterTerm) {
if (!filterTerm) {
return dummyProducts
}
return dummyProducts.filter((product) => product.includes(filterTerm))
}
function App() {
const [isPending, startTransition] = useTransition()
const [filterTerm, setFilterTerm] = useState('')
const filteredProducts = filterProducts(filterTerm)
function updateFilterHandler(event) {
// 列表資料賦值的執行等級
startTransition(() => {
setFilterTerm(event.target.value)
})
}
return (
<div id="app">
<input type="text" onChange={updateFilterHandler} />
{isPending && <p style={{ color: 'white' }}>更新列表。. </p>}
<ProductList products={filteredProducts} />
</div>
)
}
export default App
子元件:
import { useDeferredValue } from "react";
function ProductList({ products }) {
const deferredProducts = useDeferredValue(products);
return (
<ul>
{deferredProducts.map((product, index) => (
<li key={index}>{product}</li>
))}
</ul>
);
}
export default ProductList;
透過這個案例,相信你對useMemo的機制和用法一定有所掌握。
至此,關於useTransition基礎用法已經講完。