react的hooks防抖和節(jié)流的具體實(shí)現(xiàn)
一、先給面試官的“標(biāo)準(zhǔn)定義”(先聲奪人)
防抖(debounce):在事件觸發(fā)一段時(shí)間后才執(zhí)行,期間再次觸發(fā)會(huì)重新計(jì)時(shí)
節(jié)流(throttle):在固定時(shí)間內(nèi)只執(zhí)行一次
這一句一定要先說。
二、為什么在 React Hooks 里要“特別處理”?
問題本質(zhì):閉包 + 重新渲染
const fn = () => {
console.log(count)
}- 每次 render 都是新函數(shù)
- 定時(shí)器 / 事件里用的可能是舊狀態(tài)
?? 普通 JS 防抖在 Hooks 里會(huì)失效或拿到舊值
三、Hooks 防抖(推薦實(shí)現(xiàn))
1?? 最穩(wěn)方案:useRef + useCallback
function useDebounceFn(fn, delay = 300) {
const timer = useRef<number | null>(null)
const fnRef = useRef(fn)
// 始終指向最新 fn,解決閉包問題
fnRef.current = fn
const debounce = useCallback((...args) => {
if (timer.current) {
clearTimeout(timer.current)
}
timer.current = window.setTimeout(() => {
fnRef.current(...args)
}, delay)
}, [delay])
return debounce
}使用方式
const onSearch = useDebounceFn(value => {
fetchList(value)
}, 500)
<input onChange={e => onSearch(e.target.value)} />2?? 面試官加分點(diǎn)
使用 useRef 保存最新函數(shù),避免閉包導(dǎo)致狀態(tài)不更新。
四、Hooks 節(jié)流(兩種方式都要會(huì))
方案一:時(shí)間戳節(jié)流(最穩(wěn)定)
function useThrottleFn(fn, delay = 300) {
const lastTime = useRef(0)
const fnRef = useRef(fn)
fnRef.current = fn
return useCallback((...args) => {
const now = Date.now()
if (now - lastTime.current >= delay) {
lastTime.current = now
fnRef.current(...args)
}
}, [delay])
}方案二:定時(shí)器節(jié)流(常被追問)
function useThrottleFn(fn, delay = 300) {
const timer = useRef<number | null>(null)
const fnRef = useRef(fn)
fnRef.current = fn
return useCallback((...args) => {
if (timer.current) return
timer.current = window.setTimeout(() => {
fnRef.current(...args)
timer.current = null
}, delay)
}, [delay])
}兩種節(jié)流的區(qū)別(面試官愛問)
| 方式 | 特點(diǎn) |
|---|---|
| 時(shí)間戳 | 立即執(zhí)行 |
| 定時(shí)器 | 延遲執(zhí)行 |
五、為什么不用 lodash debounce?
可以用,但要說清楚限制
const debouncedFn = useMemo( () => debounce(fn, 300), [] )
? 問題:
- fn 變了,debounce 不更新
- 容易產(chǎn)生臟數(shù)據(jù)
正確用法
const fnRef = useRef(fn) fnRef.current = fn const debounced = useMemo( () => debounce((...args) => fnRef.current(...args), 300), [] )
六、Hooks 防抖節(jié)流常見坑(必背)
? 錯(cuò)誤寫法
const fn = debounce(() => {
setCount(count + 1)
}, 300)問題
- 每次 render 都創(chuàng)建新 debounce
- count 永遠(yuǎn)是舊值
? 正確認(rèn)知
- 防抖節(jié)流函數(shù)要只創(chuàng)建一次
- 執(zhí)行的函數(shù)要始終是最新的
七、什么時(shí)候用防抖?什么時(shí)候用節(jié)流?
防抖(Debounce)
- 搜索框
- 輸入聯(lián)想
- 表單校驗(yàn)
節(jié)流(Throttle)
- 滾動(dòng)
- resize
- 拖拽
八、面試終極總結(jié)(一定要背)
React Hooks 下實(shí)現(xiàn)防抖節(jié)流,關(guān)鍵不是 setTimeout,而是用 useRef 解決閉包問題,保證函數(shù)引用穩(wěn)定且狀態(tài)最新。
到此這篇關(guān)于react的hooks防抖和節(jié)流的具體實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)react hooks防抖和節(jié)流內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
解決React報(bào)錯(cuò)Functions are not valid as 
這篇文章主要為大家介紹了React報(bào)錯(cuò)Functions are not valid as a React child解決詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12
ReactNative短信驗(yàn)證碼倒計(jì)時(shí)控件的實(shí)現(xiàn)代碼
本篇文章主要介紹了ReactNative短信驗(yàn)證碼倒計(jì)時(shí)控件的實(shí)現(xiàn)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-07-07
Redux thunk中間件及執(zhí)行原理詳細(xì)分析
redux的核心概念其實(shí)很簡(jiǎn)單:將需要修改的state都存入到store里,發(fā)起一個(gè)action用來描述發(fā)生了什么,用reducers描述action如何改變state tree,這篇文章主要介紹了Redux thunk中間件及執(zhí)行原理分析2022-09-09
React啟動(dòng)時(shí)webpack版本沖突報(bào)錯(cuò)的解決辦法
在啟動(dòng)React應(yīng)用時(shí),遇到Webpack版本不匹配導(dǎo)致的運(yùn)行錯(cuò)誤,解決方法包括刪除全局及局部的webpack和webpack-cli,然后根據(jù)項(xiàng)目需求安裝特定版本的webpack,本文通過代碼示例給大家介紹的非常詳細(xì),需要的朋友可以參考下2024-09-09

