【问题标题】:Questions about useCallback hook and anonymous function关于useCallback hook和匿名函数的问题
【发布时间】:2020-01-24 10:33:53
【问题描述】:

在传递回调函数时,尤其是传递参数化函数时,我知道我应该使用useCallback钩子,因为使用匿名函数会对性能产生不利影响。

我说的匿名函数的例子是这样的。

import React, { useState } from 'react';

const Component = () => {
  const [param, setParam] = useState('');
  ...

  return (
    ...
    <SomeComponent
      onClick={() => setParam('parameter')}
      {...others}
    />
  );
}

在将匿名函数转换为使用此钩子的过程中,我遇到了“渲染过多”或无法正常工作的错误。 但具体是什么情况,什么情况我不知道。

我使用了useCallback,如下所示。

import React, { useState, useCallback } from 'react';

const Component = () => {
  const [param, setParam] = useState('');

  const handleClick = useCallback((params) => {
    setParam(params);
  },[]);

  ...
  return (
    ...
    <SomeComponent
      onClick={handleClick('parameter')}
      {...others}
    />
  );
}

但是,当使用匿名函数在useCallback 内返回时,它也可以工作。

这意味着像这里的代码。 (仅与上面的代码相比有区别。)

  const handleClick = useCallback((params) => {
    return () => setParam(params);
  },[]);

在这种情况下,我想知道如果我只是使用匿名函数而不是使用这个钩子,是否比在useCallback 中使用匿名函数更糟糕。

【问题讨论】:

  • 如果你的函数这么小,我怀疑即使使用useCallback.. 你也会获得任何性能。但是你会失去很多可读性,当 -> onClick={(params) =&gt; setParam(params)} 会做一样的。
  • @Keith 感谢您的评论。但该代码只是一个示例。也许这是一个不恰当的例子。我的问题的重点是,“仅使用匿名函数在`useCallback`中返回匿名函数时是否会造成相同的性能损失?”换句话说,人们推荐使用useCallback,因为匿名函数对性能有负面影响,而我想知道当我在`useCallback`中返回一个匿名函数时,如果它们正常工作,我是否可以使用它们。
  • 当你需要通过传递函数的相同引用来优化子重新渲染并且子组件是PureComponent/用React.memo包装时,使用useCallback,尽管它会记住之前的函数每次重新渲染时都会创建一个新函数,但会被垃圾收集。
  • 好的。感谢您的评论。帮了大忙!

标签: javascript reactjs react-hooks anonymous-function usecallback


【解决方案1】:
  const handleClick = useCallback((params) => {
    setParam(params);
  },[]);

  ...
  return (
    ...
    <SomeComponent
      onClick={handleClick('parameter')}
      {...others}
    />
  );

在上面的代码中,在第一次渲染时,在这个语句"onClick={handleClick('parameter')}"handleClick 函数被一个名为“参数”的字符串调用。由于 handleClick 具有 setParam("parameter"),它将更新状态。更新状态将导致重新渲染,这将再次出现在同一语句 "onClick={handleClick('parameter')}" 导致无限循环。

您稍后添加的以下代码有效,因为您没有更新状态,而是返回一个函数,该函数充当 onclick 处理程序。

const handleClick = useCallback((params) => {
    return () => setParam(params);
  },[]);

更好的方法应该如下,

import React, { useState, useCallback } from 'react';

const Component = () => {
  const [param, setParam] = useState('');

  const handleClick = useCallback((params) => {
    setParam(params);
  },[]);

  ...
  return (
    ...
    <SomeComponent
      onClick={handleClick}
      {...others}
    />
  );
}

回到您的问题,比较性能取决于其他函数定义和 子组件的渲染时间 在您的 Compoenent 内部的 return 函数中。 假设您的应用程序中有另一个名为“anotherHandleClick”的 onclickHanldier。 那么你的组件看起来像这样

const Component = () => {
  const [param, setParam] = useState('');
  const [anotherParam, setAnotherParam] = useState('');

  const handleClick = (params) => {
    setParam(params);
  };
const anotherHandleClick =(params) => {
    setAnotherParam(params);
  };
  ...
  return (
    ...
    <SomeComponent
      onClick={handleClick('parameter')}
      {...others}
    />
<SomeComponent
      onClick={antherHandleClick('parameter')}
      {...others}
    />
  );
}

在上述组件中,当“SomeCompoenent”中的任何一个单击整个“组件”时重新渲染,因此处理函数是新定义的。当两者都对 onclick 处理函数进行引用相等检查时,他们认为它是新的处理函数,使它们同时呈现两者。 在这种情况下,最好使用 useCallBack 钩子,如下所示,

const Component = () => {
  const [param, setParam] = useState('');
      const [anotherParam, setAnotherParam] = useState('');

  const handleClick = useCallback((params) => {
    setParam(params);
  },[]);
const anotherHandleClick = useCallback((params) => {
    setAnotherParam(params);
  },[]);
  ...
  return (
    ...
    <SomeComponent
      onClick={handleClick('parameter')}
      {...others}
    />
<SomeComponent
      onClick={antherHandleClick('parameter')}
      {...others}
    />
  );
}

在上面的代码中,当任何一个被点击时,状态会发生变化。然后在渲染时, useCallback 确保 onclick 处理程序引用没有改变。因此不会重新呈现对 onclick 处理程序的依赖。

所以最终的想法是在这两种情况下,它都会在每次渲染上创建一个函数。第二个(因为它包含在 useCallback 中)将返回在初始渲染时创建的记忆函数

何时使用 useMemo 或 useCallback refer this

【讨论】:

  • 感谢您的回答。但是正如你在第三段代码中所说的,我是在问这个问题之前写的,但是在这种情况下,它不起作用,因为没有传递任何参数。也许是因为我写的例子比我遇到的问题简单得多。所以你的意思是,如果我像我在问题中写的最后一个代码那样写,这对性能没有好处?
  • 当只有一个函数定义时,使用 useCallBack 是多余的,因为它比内联处理程序多了一个步骤。通常反应渲染非常快。但是当你的组件有多个函数定义和依赖子组件的渲染时间非常高时,最好使用useCallBack。请阅读:kentcdodds.com/blog/usememo-and-usecallback 以便更好地理解。如果您有更好的观点,请告诉我,我也可以学习。
  • 哦,我明白你的意思了。感谢您的善意评论!
  • 希望你学到了一些东西。我编辑了答案并添加了粗体描述,基本上解释了差异。不客气:)
【解决方案2】:

在您的代码中:

const handleClick = useCallback((params) => {
    setParam(params);
  },[]);

您应该像这样将参数传递给useCallback 的第二个参数:

const handleClick = useCallback((params) => {
    setParam(params);
  },[setParam,param, SETPARAMACTUALVALUE]); 
// Change SETPARAMACTUALVALUE to whatever the variable name is for the `setParam` hook

【讨论】:

  • 哎呀,我写的作为例子的代码太着急了,出错了。对不起。但我的问题的重点是,“在 useCallback 中返回匿名函数是否会像只使用匿名函数一样降低性能?”
【解决方案3】:

如果你想保存函数直到钩子的依赖改变,useCallback 钩子的使用会更好。它给你更好的性能,因为钩子记住了内部函数。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-01-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多