想要做到就要有更多的學(xué)習(xí),你知道為什么React不把他們設(shè)為默認方法#useEvent是一個剛剛提案的原生Hook,還處于RFC?,F(xiàn)在我們就一起來討論下
RFC:Request for Comments 提案應(yīng)用的還十分廣泛
我們先看看在沒有 useEvent 會出現(xiàn)的情況:
function Chat() { const [text, setText] = useState(''); // ???? Always a different function const onClick = () => { sendMessage(text); }; return <SendButton onClick={onClick} />; }
上面可以看到在點擊事件的回調(diào)函數(shù)onClick中需要讀取當(dāng)前鍵入的文本text,就會造成onClick隨著組件重新渲染一次次地重新創(chuàng)建,每次都會如此的重復(fù),對于性能損耗十分大,想要優(yōu)化看看下面:
function Chat() { const [text, setText] = useState(''); // ???? A different function whenever `text` changes const onClick = useCallback(() => { sendMessage(text); }, [text]); return <SendButton onClick={onClick} />; }
通過 useCallback 返回一個 memoized 回調(diào)函數(shù)。
useCallback: 返回一個 memoized 回調(diào)函數(shù)。 把內(nèi)聯(lián)回調(diào)函數(shù)及依賴項數(shù)組作為參數(shù)傳入useCallback,它將返回該回調(diào)函數(shù)的memoized版本,該回調(diào)函數(shù)僅在某個依賴項改變時才會更新。當(dāng)你把回調(diào)函數(shù)傳遞給經(jīng)過優(yōu)化的并使用引用相等性去避免非必要渲染(例如shouldComponentUpdate)的子組件時,它將非常有用。useCallback(fn, deps)相當(dāng)于useMemo(() => fn, deps)。
最終使得onClick的引用始終不變但是!
onClcik這個方法有需要保證每次都要拿到最新的、正確的text,所以他的deps中就自然是設(shè)置了text—— 壞了,“又回到最初的起點~”。隨著每一次keystroke,onClick又變成了上面的情況:
Always a different function
但你又不能將其從deps中移除,移除了他就只能拿到text的初始值,失去了他本該有的功能...
小 useEvent 來給他整個活????
useEvent就是為了解決此類問題,所以他干脆不要deps了,他就是一直返回一個相同的函數(shù)引用,哪怕text發(fā)生變化。當(dāng)然,保證它也能拿到最新的、正確的**text**。
function Chat() { const [text, setText] = useState(''); // ? Always the same function (even if `text` changes) const onClick = useEvent(() => { sendMessage(text); }); return <SendButton onClick={onClick} />; }
現(xiàn)在好了:
onClick 的引用始終是同一個
保證每次都能拿到最新的、正確的text
當(dāng)然還有其他一些場景,但是大致需求原理相同,就是不想讓A因為b變化而總是重新加載,但是又因為要拿到b恰當(dāng)?shù)闹担詃eps中必須b,導(dǎo)致不得不重新加載,掉進了“圈圈圓圓圈圈~”的陷阱。更多場景這里就不再贅述。更多案例可查看文末的學(xué)習(xí)資源~
總而言之,用useEvent給他裹上就是香,就是可以同時達到上面兩個效果:
引用不變
拿到恰當(dāng)?shù)闹?/p>
這是咋做到的????
說了這么多,我們來看看他這是咋做到的
他大概是這么個形狀:(不是源碼就長這樣的意思嗷)
// (!) Approximate behavior function useEvent(handler) { const handlerRef = useRef(null); // In a real implementation, this would run before layout effects useLayoutEffect(() => { handlerRef.current = handler; }); return useCallback((...args) => { // In a real implementation, this would throw if called during render const fn = handlerRef.current; return fn(...args); }, []); }
先回顧幾個Hook相關(guān)知識點:
useRef:
useRef 返回一個可變的 ref 對象,其 .current 屬性被初始化為傳入的參數(shù)(initialValue)。返回的 ref 對象在組件的整個生命周期內(nèi)持續(xù)存在。
這里通過 useRef 保存回調(diào)函數(shù)handler到handlerRef.current,然后再在 useCallback 中從handlerRef.current來取函數(shù)再調(diào)用,簡單來說就可以跳出循環(huán),打破僵局。并且不出意外的話handler在整個生命周期內(nèi)持續(xù)存在,也就是只有一個引用。
useLayoutEffect
這個useLayoutEffect可能沒那么常用,我們來看看這是啥嘞
其函數(shù)簽名與 useEffect 相同,但它會在所有的 DOM 變更之后同步調(diào)用 effect。可以使用它來讀取 DOM 布局并同步觸發(fā)重渲染。在瀏覽器執(zhí)行繪制之前,useLayoutEffect 內(nèi)部的更新計劃將被同步刷新。
useEffect
回顧一下useEffect
默認情況下,effect 將在每輪渲染結(jié)束后執(zhí)行
兩者的區(qū)別
好了,現(xiàn)在我給你用一個字總結(jié)一下兩者區(qū)別,useLayoutEffect更“快”!這個“塊”不是速度更快,而是他“搶跑”了哩。useLayoutEffect是在render之前同步執(zhí)行,useEffect在render之后異步執(zhí)行,這里就是保證useLayoutEffect里的回調(diào)肯定比useEffect更早前被調(diào)用、被執(zhí)行。
useCallback執(zhí)行時機
之前就有說道useCallback(fn, deps)相當(dāng)于useMemo(() => fn, deps)。
文檔里是這樣說useMemo的:
記住,傳入 useMemo 的函數(shù)會在渲染期間執(zhí)行。請不要在這個函數(shù)內(nèi)部執(zhí)行與渲染無關(guān)的操作,諸如副作用這類的操作屬于 useEffect 的適用范疇,而不是 useMemo。
也就是他是在render時執(zhí)行的,也就是保證了賦值handler給handlerRef.current是在前面發(fā)生
想要了解一個東西,先了解它的作用。一個useCallback包裹后memoized函數(shù),其中從handlerRef.current中獲取函數(shù),并且deps為[],這就表明不會再次更新。
捋一捋????
現(xiàn)在我們重新看下,關(guān)于useEvent方法,總結(jié)就是:它接收一個回調(diào)函數(shù)handler作為參數(shù),提供給你一個穩(wěn)定的函數(shù)(始終只有一個引用)并且調(diào)用時都是用的你傳入的最新的參數(shù)...args——比如前面案例中的text,始終都是最新的、正確的、恰當(dāng)?shù)摹?/strong>再結(jié)合一開始的案例,大概流程就是這樣:
好的,都已說完了,大家多多學(xué)習(xí),有更多的成長幫助。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/128187.html
陷進到處都是啊!本篇文章就說說Hooks使用時存在所謂的閉包陷阱,看看下面代碼: functionChat(){ const[text,setText]=useState(''); constonClick=useCallback(()=>{ sendMessage(text); },[]); return<SendButtononClick=...
想必大家都能看得懂的源碼 ahooks 整體架構(gòu)篇,且可以使用插件化機制優(yōu)雅的封裝你的請求hook,現(xiàn)在我們就探討下ahooks 是怎么解決 React 的閉包問題的?。 React 的閉包問題 先來看一個例子: importReact,{useState,useEffect}from"react"; exportdefault()=>{ const[c...
大家會發(fā)現(xiàn),自從 React v16.8 推出了 Hooks API,前端框架圈并開啟了新的邏輯復(fù)用的時代,從此無需在意 HOC 的無限套娃導(dǎo)致性能差的問題,同時也解決了 mixin 的可閱讀性差的問題。這里也有對于 React 最大的變化是函數(shù)式組件可以有自己的狀態(tài),扁平化的邏輯組織方式,更加友好地支持 TS 類型聲明。 在運用Hooks的時候,除了 React 官方提供的,同時也支持我們...
摘要:更容易將組件的與狀態(tài)分離。也就是只提供狀態(tài)處理方法,不會持久化狀態(tài)。大體思路是利用共享一份數(shù)據(jù),作為的數(shù)據(jù)源。精讀帶來的約定函數(shù)必須以命名開頭,因為這樣才方便做檢查,防止用判斷包裹語句。前端精讀幫你篩選靠譜的內(nèi)容。 1 引言 React Hooks 是 React 16.7.0-alpha 版本推出的新特性,想嘗試的同學(xué)安裝此版本即可。 React Hooks 要解決的問題是狀態(tài)共享,...
摘要:注冊方法之后,當(dāng)執(zhí)行了當(dāng)前的,那么掛載正在當(dāng)前上的方法就會被執(zhí)行。比如在開始編譯之前,就能觸發(fā)鉤子,就用到了當(dāng)前的。上面都是前置知識,下面通過解讀一個源碼來鞏固下。先看一段簡單的源碼。,是眾多的的一個,官網(wǎng)的解釋是編譯創(chuàng)建之后,執(zhí)行插件。 通過解讀webpack-manifest-plugin,了解下plugin機制 先簡單說一下這個插件的功能,生成一份資源清單的json文件,如下 s...
閱讀 570·2023-03-27 18:33
閱讀 761·2023-03-26 17:27
閱讀 658·2023-03-26 17:14
閱讀 612·2023-03-17 21:13
閱讀 546·2023-03-17 08:28
閱讀 1836·2023-02-27 22:32
閱讀 1330·2023-02-27 22:27
閱讀 2212·2023-01-20 08:28