簡體   English   中英

在 React.memo 中需要 useCallback 嗎?

[英]useCallback necessary within React.memo?

考慮這個例子:

import React, { useCallback } from 'react';

type UserInputProps = {
  onChange: (value: string) => void;
};

const UserInput = React.memo(({ onChange }: UserInputProps) => {
  // Is this `useCallback` redundant?
  const handleChange = useCallback(
    (event) => {
      onChange(event.target.value);
    },
    [onChange]
  );

  return <input type="text" onChange={handleChange} />;
});

export default UserInput;

我的問題是:

  1. 當 props 僅包含onChange而沒有其他元素時,在這種情況下是否不需要useCallback ,因為整個組件已經基於onChange進行了備忘錄?
  2. 如果我們添加一個額外的道具(比如<input>的初始value的值),那么我認為useCallback變得有用,因為否則即使onChange沒有改變但value改變了,也會重新創建handleChange 那是對的嗎?

當 props 僅包含onChange而沒有其他元素時,在這種情況下是否不需要useCallback ,因為整個組件已經基於onChange進行了備忘錄?

它是基於所有道具記憶的,而不僅僅是onChange 是的, useCallback在那里是不必要的。

如果我們添加一個額外的道具(比如<input>的初始value的值),那么我認為useCallback變得有用,因為否則即使onChange沒有改變但值改變了,也會重新創建handleChange 那是對的嗎?

如果你想在更新input時更新value而不是更新onChange ,你可以為你的 props 添加value並繼續為你的handleChange useCallback如果你願意,這樣 React 就不必換入新的事件處理程序當它設置值時;我的印象是這通常是矯枉過正的)。 例如:

const UserInput = React.memo(({ onChange, value }: UserInputProps) => {
  const handleChange = useCallback(
    (event) => {
      onChange(event.target.value);
    },
    [onChange]
  );

  return <input type="text" value={value} onChange={handleChange} />;
});

如果onChange道具沒有改變,那將使用最新的value並重用之前的handleChange

在這種情況下,您可能不會保留React.memo ,如果您期望該value會因onChange而改變。 也就是說,如果您希望每次調用組件時該value都會有所不同,那么React.memo對 props 的檢查是您可能不會保留的額外工作:

const UserInput = ({ onChange, value }: UserInputProps) => {
  const handleChange = useCallback(
    (event) => {
      onChange(event.target.value);
    },
    [onChange]
  );

  return <input type="text" value={value} onChange={handleChange} />;
};

但是如果你希望React.memo繼續檢查 props 並且在 props 都沒有變化時不調用你的 function,你可以保留它。

如果你只是想為你的組件提供初始值然后在本地控制它,你可以繼續使用React.memo (因為它仍然為相同的輸入道具呈現相同的東西),在這種情況下你不需要useCallback

const UserInput = React.memo(({ onChange, initialValue }: UserInputProps) => {
  const [value, setValue] = useState(initialValue);
  const handleChange = (event) => {
    setValue(event.target.value);
    onChange(event.target.value);
  };

  return <input type="text" value={value} onChange={handleChange} />;
});

只有當onChangeinitialValue改變時才會被調用。 您也可以在那里使用useCallback ,以便再次僅在onChange道具更改時更新input上的onChange ,以避免 React 刪除舊處理程序並在value更改時設置新處理程序:

const UserInput = React.memo(({ onChange, initialValue }: UserInputProps) => {
  const [value, setValue] = useState(initialValue);
  const handleChange = useCallback(
    (event) => {
      setValue(event.target.value);
      onChange(event.target.value);
    },
    [onChange]
 );

  return <input type="text" value={value} onChange={handleChange} />;
});

旁注:要記住的一件事是,每次調用組件 function 時都會創建一個新的handleChange function ,即使您使用的是useCallback 它必須是,所以它可以作為參數傳遞給useCallback 唯一的區別是您是使用新的 function,還是第一次創建的原始的( useCallback的結果)。 我認為重用為給定的一組依賴項創建的第一個依賴項的原因是最小化傳遞給子組件的更改。

當 props 僅包含onChange而沒有其他元素時,在這種情況下是否不需要useCallback ,因為整個組件已經基於 onChange 進行了備忘錄?

不,可能有必要memouseCallback的目的不同。

如果沒有useCallback ,您可能在每次渲染時都有“大量計算”:

“大量計算”是指一般情況,而不是僅傳遞事件值的特定示例。

const UserInput = React.memo(({ onChange = () => {} }) => {
  // Uncomment for memoization
  // Note that you can implement useCallback with useMemo

  // const handleChange = useMemo(() => {
  //   console.log("heavy computation memoized");
  //   return event => {
  //     onChange(event.target.value);
  //   };
  // }, [onChange]);

  const handleChange = event => {
    // Here we can have some heavy computation
    // Not related to this specific usecase
    console.log("heavy computation on every render");
    onChange(event.target.value);
  };

  return <input type="text" onChange={handleChange} />;
});

如果我們添加一個額外的道具(比如 的初始值的值),那么我認為useCallback變得有用,因為否則即使 onChange 沒有改變但值改變了,也會重新創建handleChange 那是對的嗎?

如果您要使用受控組件(由於使用inputvalue屬性),initialValue將被初始化一次,因此嘗試記住它是毫無用處的(出於什么目的?):

const UserInputWithValue = ({ onChange, initialValue }) => {
  // initilized once, no need to memoize
  const [value,setValue] = useState(initialValue);
  const handleChange = useCallback(
    (event) => {
      setValue(event.target.value)
      onChange(event.target.value);
    },
    [onChange]
  );

  // Controlled
  return <input type="text" value={value} onChange={handleChange} />;
};

編輯objective-brown-nyuyc

暫無
暫無

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

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