繁体   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