React.useCallback 记忆柯里化函数了吗?

Does React.useCallback memoize curried functions?

我有时会在 useCallback.

中声明柯里化函数时使用这种模式
const Child = ({ handleClick }) => {
  return (
    <>
      <button onClick={handleClick("foo")}>foo</button>
      <button onClick={handleClick("lorem")}>lorem</button>
    </>
  );
};

export default function App() {
  const [state, setState] = useState("");

  const handleClick = useCallback(
    (newState) => () => {
      setState(newState);
    },
    []
  );

  return (
    <div className="App">
      <Child handleClick={handleClick} />
      <p>{state}</p>
    </div>
  );
}

因为我想将参数从 JSX 传递到事件处理程序并避免使用多个处理程序。

当组件重新渲染时,将调用handleClick并将返回的函数分配给onClickprop,但每次都是新函数还是嵌套函数也被 useCallback?

记住了

PS:这是一个简单的例子。假设 useCallback 具有多个依赖项的用法

应该吧,不管是不是curry,都是一个函数实例,只要你想保留一个旧的函数实例,都可以用。

但是不要因为属性 onClick 而使用它,因为当你的组件呈现时,这个 button 必须呈现而不管 onClick。所以你的行可以简单地写成

  const onClick = value => () => { setState(value) }

或者您甚至可以将其提升为全局函数。

  const handle = setState => value => () => { setState(value) }

注意:我不想说 useCallback 大多数时间都是无用的。但实际上,如果您不知道为什么要使用 useMemo,请不要使用 useCallback。它们旨在跳过分配,但不是为了跳过渲染,或者在您的情况下,是为了提高可重用性。 (不是为了这个目的)。

编辑

以下答案指的是 OP 代码的 initial version,其中 handleClick 未作为道具传递给 Child 组件。


在这种情况下你并不需要 useCallback

实际上,在这种情况下最好不要使用 useCallback 挂钩,因为:

  1. 传递给 useCallback 的回调函数会在您的组件每次重新呈现时创建。结果,无论如何都会创建一个新函数,就像不使用 useCallback

    一样
  2. 获取 handleClick 函数的记忆版本对您的情况没有任何好处。如果将 handleClick 作为 prop 传递给子组件,记忆将很有用。

...but will it be a new function every time or will the nested function also get memoized by useCallback?

不,嵌套函数不会被记忆。

handleClick 是一个记忆函数,但那个记忆函数 returns 每次执行时都是一个新函数。

调用 handleClick 就像调用任何其他函数一样 - 每次调用时都会创建在函数体内声明的任何内容。