2

在传递回调函数时,尤其是传递参数化函数时,我知道应该使用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如果我只是使用匿名函数而不是使用这个钩子,是否比在内部使用匿名函数更糟糕。

4

3 回答 3

3
  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}
    />
  );
}

回到您的问题,比较性能取决于您的组件内的返回函数内的其他函数定义和子组件的渲染时间。假设您的应用程序中有另一个名为“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参考这个

于 2020-01-24T11:07:35.440 回答
0

在您的代码中:

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
于 2020-01-24T10:38:14.613 回答
0

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

于 2020-01-24T10:38:22.153 回答