溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

useEvent降低Hooks負(fù)擔(dān)的原生Hook分析

發(fā)布時(shí)間:2022-07-13 09:17:57 來源:億速云 閱讀:142 作者:iii 欄目:開發(fā)技術(shù)

這篇文章主要講解了“useEvent降低Hooks負(fù)擔(dān)的原生Hook分析”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“useEvent降低Hooks負(fù)擔(dān)的原生Hook分析”吧!

沒有 useEvent 的時(shí)候

我們先看看不用 useEvent 的情況:

function Chat() {
  const [text, setText] = useState('');
  // ???? Always a different function
  const onClick = () => {
    sendMessage(text);
  };
  return <SendButton onClick={onClick} />;
}

其中點(diǎn)擊事件的回調(diào)函數(shù) onClick 中需要讀取當(dāng)前鍵入的文本text,這里的onClick隨著組件重新渲染一次次地重新創(chuàng)建,每次都會(huì)是不一樣的引用,這顯然帶來了性能損耗,如果你想對(duì)其進(jìn)行優(yōu)化,你可能會(huì)這樣做:

function Chat() {
  const [text, setText] = useState('');
  // ???? A different function whenever `text` changes
  const onClick = useCallback(() => {
    sendMessage(text);
  }, [text]);
  return <SendButton onClick={onClick} />;
}

通過 useCallback 返回一個(gè) memoized 回調(diào)函數(shù)。

useCallback: 返回一個(gè) memoized 回調(diào)函數(shù)。 把內(nèi)聯(lián)回調(diào)函數(shù)及依賴項(xiàng)數(shù)組作為參數(shù)傳入 useCallback,它將返回該回調(diào)函數(shù)的 memoized 版本,該回調(diào)函數(shù)僅在某個(gè)依賴項(xiàng)改變時(shí)才會(huì)更新。當(dāng)你把回調(diào)函數(shù)傳遞給經(jīng)過優(yōu)化的并使用引用相等性去避免非必要渲染(例如 shouldComponentUpdate)的子組件時(shí),它將非常有用。 useCallback(fn, deps) 相當(dāng)于 useMemo(() => fn, deps)。

最終使得onClick的引用始終不變但是!

onClcik這個(gè)方法有需要保證每次都要拿到最新的、正確的text,所以他的deps中就自然是設(shè)置了text&mdash;&mdash; 壞了,“又回到最初的起點(diǎn)~”。隨著每一次keystroke,onClick又變成了上面的情況:

 Always a different function

但你又不能將其從deps中移除,移除了他就只能拿到text的初始值,失去了他本該有的功能...

小 useEvent 來給他整個(gè)活

useEvent就是為了解決此類問題,所以他干脆不要deps了,他就是一直返回一個(gè)相同的函數(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 的引用始終是同一個(gè)

  • 保證每次都能拿到最新的、正確的 text

當(dāng)然還有其他一些場(chǎng)景,但是大致需求原理相同,就是不想讓A因?yàn)?code>b變化而總是重新加載,但是又因?yàn)橐玫?code>b恰當(dāng)?shù)闹?,所?code>deps中必須b,導(dǎo)致不得不重新加載,掉進(jìn)了“圈圈圓圓圈圈~”的陷阱。更多場(chǎng)景這里就不再贅述。更多案例可查看文末的學(xué)習(xí)資源~

總而言之,用useEvent給他裹上就是香,就是可以同時(shí)達(dá)到上面兩個(gè)效果:

  • 引用不變

  • 拿到恰當(dāng)?shù)闹?/p>

這是咋做到的????

說了這么多,我們來看看他這是咋做到的
大概是這么個(gè)形狀:(不是源碼就長(zhǎng)這樣的意思嗷)

// (!) 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);
  }, []);
}

先回顧幾個(gè)Hook相關(guān)知識(shí)點(diǎn):

useRef

useRef:

useRef 返回一個(gè)可變的 ref 對(duì)象,其 .current 屬性被初始化為傳入的參數(shù)(initialValue)。返回的 ref 對(duì)象在組件的整個(gè)生命周期內(nèi)持續(xù)存在。

這里通過 useRef 保存回調(diào)函數(shù)handlerhandlerRef.current,然后再在 useCallback 中從handlerRef.current來取函數(shù)再調(diào)用,這樣避免了直接調(diào)用,跳出了閉包陷阱。并且不出意外的話handler在整個(gè)生命周期內(nèi)持續(xù)存在,也就是只有一個(gè)引用

useLayoutEffect

這個(gè) useLayoutEffect 可能沒那么常用,我們來看看這是啥嘞

其函數(shù)簽名與 useEffect 相同,但它會(huì)在所有的 DOM 變更之后同步調(diào)用 effect??梢允褂盟鼇碜x取 DOM 布局并同步觸發(fā)重渲染。在瀏覽器執(zhí)行繪制之前,useLayoutEffect 內(nèi)部的更新計(jì)劃將被同步刷新。

useEffect

回顧一下 useEffect

默認(rèn)情況下,effect 將在每輪渲染結(jié)束后執(zhí)行

兩者的區(qū)別

好了,現(xiàn)在我給你用一個(gè)字總結(jié)一下兩者區(qū)別,useLayoutEffect 更“快”!這個(gè)“塊”不是速度更快,而是他“搶跑”了哩。useLayoutEffect 是在render之前同步執(zhí)行,useEffectrender之后異步執(zhí)行,這里就是保證useLayoutEffect 里的回調(diào)肯定比useEffect更早前被調(diào)用、被執(zhí)行。

useCallback執(zhí)行時(shí)機(jī)

前面說到

useCallback(fn, deps) 相當(dāng)于 useMemo(() => fn, deps)。

文檔里是這樣說 useMemo 的:

記住,傳入 useMemo 的函數(shù)會(huì)在渲染期間執(zhí)行。請(qǐng)不要在這個(gè)函數(shù)內(nèi)部執(zhí)行與渲染無關(guān)的操作,諸如副作用這類的操作屬于 useEffect 的適用范疇,而不是 useMemo。

也就是他是在render時(shí)執(zhí)行的,也就是保證了賦值handlerhandlerRef.current是在前面發(fā)生

這里的作用

這里返回的是一個(gè)useCallback包裹后 memoized函數(shù),其中從handlerRef.current中獲取函數(shù),并且deps[],也就是說他不會(huì)再次更新。

感謝各位的閱讀,以上就是“useEvent降低Hooks負(fù)擔(dān)的原生Hook分析”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對(duì)useEvent降低Hooks負(fù)擔(dān)的原生Hook分析這一問題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI