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