【问题标题】:Does React.useCallback memoize curried functions?React.useCallback 会记忆 curried 函数吗?
【发布时间】:2021-11-07 16:44:50
【问题描述】:

我有时会使用这种模式,在 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 将被调用并将返回的函数分配给 onClick 属性,但它是否每次都是一个新函数或者嵌套函数也会被 @987654327 记忆@?

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

【问题讨论】:

    标签: javascript reactjs memoization


    【解决方案1】:

    编辑

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


    在这种情况下,你真的不需要useCallback。

    其实这种情况下最好不要使用useCallback钩子,因为:

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

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

    ...但是每次都会是一个新函数还是嵌套的 函数也被 useCallback 记住了?

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

    handleClick 是一个记忆函数,但记忆函数每次执行时都会返回一个新函数。

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

    【讨论】:

    • 我用了一个简单的例子,但想象一个 useCallback 有几个依赖项
    • 每次重新渲染组件时都会创建传递给 useCallback 的函数。为什么,一个空数组作为钩子中的第二个参数传递。
    • @RohitSharma 空依赖数组不会阻止评估回调函数。创建了一个新函数,但useCallback 将丢弃它并返回一个记忆函数。 useCallback(() =&gt; {}, []) 的计算方式与任何其他函数调用表达式一样。每次调用useCallback 时都会创建匿名回调函数。
    • 因此,在按钮位于子组件中的情况下,如果 handleClick 作为道具传递,我们获得的唯一优势是组件不会重新渲染,因为 handleClick不会改变。对吗?
    • @RameshReddy 是的,完全正确。如果handleClick 被添加到子组件的useCallback 或useEffect 钩子的依赖数组中,那么handleClick 的记忆版本将防止useEffect 钩子的不必要执行和不必要的记忆函数的创建子组件。
    【解决方案2】:

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

    但是不要因为prop onClick而使用它,因为当你的组件渲染时,这个button必须渲染而不管onClick。所以你的线可以简单地为

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

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-06-02
      • 2023-03-12
      • 1970-01-01
      • 1970-01-01
      • 2010-12-04
      • 2015-04-23
      • 2020-11-07
      • 2018-09-18
      相关资源
      最近更新 更多