簡體   English   中英

這是對 useCallback 和 useMemo 的錯誤使用嗎?

[英]Is this incorrect use of useCallback and useMemo?

我們什么時候應該擔心函數組件重新定義變量和函數?

我認為第一種情況顯然是不必要的,創建函數並不昂貴(並且反應開發工具配置文件測試沒有檢測到 useCallback 的性能變化)

import React, { useState, useMemo, useCallback } from "react";

export const App = () => {
  const [counter, setCounter] = useState(1);

  const showCounter = useCallback(() => {
    console.log(counter);
  }, [counter]);

  return (
    <>
      <button onClick={showCounter}>Show</button>
      <button onClick={() => setCounter(counter + 1)}>Add</button>
    </>
  );
};

另一方面,在另一個示例中,使用 react 開發工具,我們可以檢測到 useMemo 將渲染時間縮短了一半:

import React, { useState, useMemo, useCallback } from "react";

export const App = () => {
  const [counter, setCounter] = useState(1);

  const [list, setList] = useState<number[]>([]);

  function setListItem(item: number) {
    setList([...list, item]);
  }

  //should we useMemo here?
  const domList = useMemo(
    () =>
      list.map((value: number, index: number) => (
        <li key={index}> {value} </li>
      )),
    [list]
  );

  return (
    <>
      <p>{counter}</p>
      <button onClick={() => setCounter(counter - 1)}>Subtract</button>
      <button onClick={() => setCounter(counter + 1)}>Add</button>
      <button onClick={() => setListItem(counter)}>Push to array</button>
      <h1>List</h1>
      <ul>{domList}</ul>
    </>
  );
};

但是當我們談論前端時,仍然不到一毫秒的增益和數組映射和 JSX 數組也不是很昂貴的東西。 但是,在每個渲染中運行一個數組 map 方法是很不舒服的。 那么,這些事情我們應該怎么做呢? (讓我們忘記什么時候我們有 useEffect 依賴於一些使 useMemo 成為必要的變量)

  • 所有不需要在每次渲染中重新定義的函數和變量中的 useCallback 和 useMemo。
  • useCallback 和 useMemo 僅用於我們可以清楚地看到性能提升的事情(即使大多數時間都不能算作對 UX 的改進)。 所以在第二個例子中我們需要 useMemo。
  • 僅當在特定情況下不使用 useCallback 和 useMemo 時,我們會得到很大的用戶體驗下降。 所以只有真正昂貴的函數才會使用回調

您獲得的性能是不同的。 是的,對於useMemo如果您正在記憶的計算很昂貴,它提供了明顯的直接好處。 但是,對於useCallbackuseMemo ,長期的好處是避免了子組件中不必要的渲染,而不是重新計算的成本。

請記住,如果組件中的任何道具發生變化,它們可能會觸發渲染調用,並且在組件樹中越靠前,它對性能的影響就越大。 這就是我們通常使用這些鈎子的原因。

一般來說,組件有幾個 state 元素,通過備忘錄掛鈎,我們可以建立依賴關系以避免計算冗余。 例如,在您的合成案例中,您有兩個 state 元素: counterlist 每次counter更改時,您都會通過使其僅依賴於list來防止重新計算domList 如果這是一個葉節點,那么肯定沒有性能提升,但是,這是組件樹的根,如果沒有這些鈎子,性能將不會隨着您添加更多 state 元素而擴展,您將不得不重構代碼以解決性能問題。 當然,如果列表包含超過 1000 個元素, <ul>{domList}</ul>的成本可能會很高,但<ul><ExpensiveCutie domList={domList} /></ul>可能需要數周時間才能注意到、調試、和重構。

簡而言之,我建議在容器組件中使用備忘錄掛鈎,而不是在葉組件中。 然而,如果你的葉子組件在你實現它的時候變成了一個容器呢?

在你 go 之前,你甚至需要使用 memo() 嗎? 在這里閱讀更多。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM