簡體   English   中英

React Hooks useCallback 的簡單示例有問題

[英]Trouble with simple example of React Hooks useCallback

我正在嘗試制作一個簡單的示例,該示例遵循頁面https://reactjs.org/docs/hooks-reference.html#usecallback文檔中的 React Hooks 示例

在沒有useCallback的情況下,代碼可以在本例中找到:

import React, { useCallback } from "react";

function Test(props) {
  function doSomething(a, b) {
    console.log("doSomething called");
    return a + b;
  }

  return (
    <div>
      {Array.from({ length: 3 }).map(() => (
        <div>{doSomething('aaa','bbb')}</div>
      ))}
    </div>
  );
}

export default Test;

但是,當我如下添加我認為正確的useCallback代碼時,出現錯誤(a 未定義)

import React, { useCallback } from "react";

function Test(props) {
  function doSomething(a, b) {
    console.log("doSomething called");
    return a + b;
  }

  const memoizedCallback = useCallback(
    () => {
      doSomething(a, b);
    },
    [a, b]
  );

  return (
    <div>
      {Array.from({ length: 3 }).map(() => (
        <div>{memoizedCallback("aaa", "bbb")}</div>
      ))}
    </div>
  );
}

export default Test;

問題代碼在這里:

https://stackblitz.com/edit/react-usememo2?file=Hello.js

useCallback的目的是能夠利用當前范圍內的道具或狀態,並且可能會在重新渲染時發生變化。 當你需要新版本的回調函數時,dependency-array 會告訴 React。 如果你想記住一個昂貴的計算,你需要使用useMemo代替。

下面的示例演示了useCallbackuseMemo之間的useCallback以及不使用它們的后果。 在這個例子中,我使用React.memo來防止Child重新渲染,除非它的 props 或 state 發生變化。 這允許看到useCallback的好處。 現在,如果Child收到一個新的onClick道具,它將導致重新渲染。

Child 1 正在接收一個非記憶化的onClick回調,因此每當父組件重新渲染時,Child 1 總是會收到一個新的onClick函數,因此它會被迫重新渲染。

Child 2 使用從useCallback返回的 memoized onClick回調,Child 3 使用等效的useMemo來演示

useCallback(fn,inputs) 等價於 useMemo(() => fn,inputs)

對於 Child 2 和 3,每次單擊 Child 2 或 3 時,回調仍然會執行, useCallback只是確保在依賴項未更改時傳遞相同版本的onClick函數。

顯示的以下部分有助於指出正在發生的事情:

nonMemoizedCallback === memoizedCallback: false|true

另外,我將使用useMemo顯示somethingExpensiveBasedOnA和記憶版本。 出於演示的目的,我使用了不正確的依賴陣列(我故意冷落b ),這樣你可以看到memoized版本並不會隨着b的變化,但它確實發生了改變,當a變化。 每當ab更改時,非記憶版本就會更改。

import ReactDOM from "react-dom";

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

const Child = React.memo(({ onClick, suffix }) => {
  const numRendersRef = useRef(1);
  useEffect(() => {
    numRendersRef.current++;
  });

  return (
    <div onClick={() => onClick(suffix)}>
      Click Me to log a and {suffix} and change b. Number of Renders:{" "}
      {numRendersRef.current}
    </div>
  );
});
function App(props) {
  const [a, setA] = useState("aaa");
  const [b, setB] = useState("bbb");

  const computeSomethingExpensiveBasedOnA = () => {
    console.log("recomputing expensive thing", a);
    return a + b;
  };
  const somethingExpensiveBasedOnA = computeSomethingExpensiveBasedOnA();
  const memoizedSomethingExpensiveBasedOnA = useMemo(
    () => computeSomethingExpensiveBasedOnA(),
    [a]
  );
  const nonMemoizedCallback = suffix => {
    console.log(a + suffix);
    setB(prev => prev + "b");
  };
  const memoizedCallback = useCallback(nonMemoizedCallback, [a]);
  const memoizedCallbackUsingMemo = useMemo(() => nonMemoizedCallback, [a]);
  return (
    <div>
      A: {a}
      <br />
      B: {b}
      <br />
      nonMemoizedCallback === memoizedCallback:{" "}
      {String(nonMemoizedCallback === memoizedCallback)}
      <br />
      somethingExpensiveBasedOnA: {somethingExpensiveBasedOnA}
      <br />
      memoizedSomethingExpensiveBasedOnA: {memoizedSomethingExpensiveBasedOnA}
      <br />
      <br />
      <div onClick={() => setA(a + "a")}>Click Me to change a</div>
      <br />
      <Child onClick={nonMemoizedCallback} suffix="1" />
      <Child onClick={memoizedCallback} suffix="2" />
      <Child onClick={memoizedCallbackUsingMemo} suffix="3" />
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

編輯 useCallback 和 useMemo

這是一個相關的答案: React Hooks useCallback 導致孩子重新渲染

=>之后有多余的{ } ,從而創建了一個塊和作用域,只需將它們刪除; 也使它成為一個聲明。 否則將參數傳遞給它,請使用此

    const memoizedCallback = useCallback(
    () => doSomething(a, b)
    ,
    [a, b]
  );

它說undefined因為=> { }的范圍沒有收到a,b 希望對您有所幫助。

暫無
暫無

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

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