onCallback React Hook - 最佳实践查询

onCallback React Hook - best practice query

这更像是一个最佳实践问题。但是我想知道 React 组件中的任何内联函数是否通常应该用 onCallback 包装以提高性能?在什么情况下我不会用 onCallback 包装这样的函数?

例如:

const ToolSearch = (props: ToolsSearchProps) => {

 const handleOnClick = () => {
    alert('do something');
 }
  
  return (
    <NoCardOverflow>
        <ToolSearchCollapse openState={filtersOpen} onClick={handleOnClick} />
    </NoCardOverflow>
  );
};

在这个例子中我应该这样做:

   const ToolSearch = (props: ToolsSearchProps) => {

     const handleOnClick = useCallback(() => {
        alert('do something');
     },[]);
      
      return (
        <NoCardOverflow>
            <ToolSearchCollapse openState={filtersOpen} onClick={handleOnClick} />
        </NoCardOverflow>
      );
    };

ToolSearchCollapse 是您的 child 组件,因此包装您的 handleClick 函数很有意义。因为每次 parent 组件 re-renders 都会将 handleclick 的新引用传递给 ToolSearchCollapse,并且您的 child 将 re-render时间 parent 状态发生变化(从未传递到 child 的状态)。使用 useCallback 将不允许创建新引用,因此您可以控制 child 应该呈现的时间。

如果您不将此 fn 传递给 child,我看不出有任何理由使用 useCallback。

我将尝试用一个例子来解释 useCallBack。我们都知道 useCallBack 的定义,但是 何时使用 是这里的技巧部分。那么,让我举个例子。

const RenderText = React.memo(({ text }) => {
  console.log(`Render ${text}`);
  return (<div>{text}</div>);
});

const App = () => {
  const [count, updateCount] = React.useState(0);
  const [lists, updateLists] = React.useState(["list 1"]);

  const addListItem = () => {
    updateLists([...lists, "random"]);
  };

  return (
    <div>
      {`Current Count is ${count}`}
      <button onClick={() => updateCount((prev) => prev + 1)}>Update Count</button>

      {lists.map((item: string, index: number) => (
        <RenderText key={index} text={item} />
      ))}
    </div>
  );
};

ReactDOM.render(<App />, document.querySelector("#app"));

jsFiddle: https://jsfiddle.net/enyctuLp/1/

上面有两种状态

  • count - 数量
  • 列表-数组

RenderText 只是呈现传递给它的文本。 (这是列表中的项目)。如果你点击Update Count按钮,RenderText不会re-render因为它独立于主要组件(App)并且在updateCount期间,只有App 组件将 re-render,因为它需要更新 count 值。

现在,将 addListItem 传递给 RenderText 组件并单击 Update Count 按钮,看看会发生什么。

jsFiddle: https://jsfiddle.net/enyctuLp/2/

你可以看到 RenderText 将 re-render 即使 list 数组没有变化,这是 BECAUSE

  • 更新计数后,App 将 re-render
  • 这将 re-render addListItem
  • 这导致 RenderText 到 re-render。

为了避免这种情况,我们应该使用 useCallBack 钩子。

jsFiddle: https://jsfiddle.net/enyctuLp/4/

现在,addListItem 函数已经被记忆化,它只会在依赖关系发生变化时发生变化。