React如何原生實現(xiàn)防抖?
作者:卡頌
簡介:《React技術(shù)揭秘》作者
來源:SegmentFault 思否社區(qū)
大家好,我卡頌。
作為前端,想必你對防抖(debounce)、節(jié)流(throttle)這兩個概念不陌生。
在React18中,基于新的并發(fā)特性,React原生實現(xiàn)了防抖的功能。
今天我們來聊聊這是如何實現(xiàn)的。
useTransition Demo
useTransition是一個新增的原生Hook,用于以較低優(yōu)先級執(zhí)行一些更新。
在我們的Demo中有ctn與num兩個狀態(tài),其中ctn與輸入框的內(nèi)容受控。
當觸發(fā)輸入框onChange事件時,會同時觸發(fā)ctn與num狀態(tài)變化。其中觸發(fā)num狀態(tài)變化的方法(即updateNum)被包裹在startTransition中:
function App() {
const [ctn, updateCtn] = useState('');
const [num, updateNum] = useState(0);
const [isPending, startTransition] = useTransition();
return (
<div >
<input value={ctn} onChange={({target: {value}}) => {
updateCtn(value);
startTransition(() => updateNum(num + 1))
}}/>
<BusyChild num={num}/>
</div>
);
}
num會作為props傳遞給BusyChild組件。在BusyChild中通過while循環(huán)人為增加組件render所消耗的時間:
const BusyChild = React.memo(({num}: {num: number}) => {
const cur = performance.now();
// 增加render的耗時
while (performance.now() - cur < 300) {}
return <div>{num}</div>;
})
所以,在輸入框輸入內(nèi)容時能明顯感到卡頓。

在線示例地址:https://codesandbox.io/s/immutable-glade-u0m6vv
按理說,onChange中會同時觸發(fā)ctn與num的狀態(tài)變化,他們在視圖中的顯示應(yīng)該是同步的。
然而實際上,輸入框連續(xù)輸入一段文字(即ctn的狀態(tài)變化連續(xù)展示在視圖中)后,num才會變化一次。
如下圖,初始時輸入框沒有內(nèi)容,num為0:

輸入框輸入很長一段文字后,num才變?yōu)?:

這種效果就像:被startTransition包裹的更新都有防抖的效果一樣。
這是如何實現(xiàn)的呢?
什么是lane
在React18中有一套更新優(yōu)先級機制,不同地方觸發(fā)的更新?lián)碛胁煌瑑?yōu)先級。優(yōu)先級的定義依據(jù)是符合用戶感知的,比如:
用戶不希望輸入框輸入文字會有卡頓,所以onChange事件中觸發(fā)的更新是同步優(yōu)先級(最高優(yōu))
用戶可以接受請求發(fā)出到返回之間有等待時間,所以useEffect中觸發(fā)的更新是默認優(yōu)先級
const SyncLane = 0b0000000000000000000000000000001;
const DefaultLane = 0b0000000000000000000000000010000;
// 用“按位或”操作合并lane
const lanes = SyncLane | DefaultLane;entangle機制
可以看到,lane機制本質(zhì)上就是各種位運算,可以設(shè)計的很靈活。

onChange={({target: {value}}) => {
updateCtn(value);
startTransition(() => updateNum(num + 1))
}
updateCtn(value)由于在onChange中觸發(fā),優(yōu)先級為SyncLane
updateNum(num + 1)由于在startTransition中觸發(fā),優(yōu)先級為TransitionLanes中的某一個
SyncLane由于是最高優(yōu)先級,會被執(zhí)行,所以我們會看到輸入框中內(nèi)容變化
TransitionLanes相關(guān)lane優(yōu)先級比SyncLane低,暫時不會執(zhí)行,同時他們會產(chǎn)生糾纏
總結(jié)
lane模型
entangle機制
更新過期機制

