12

将回调传递给组件时,我应该使用useCallback钩子返回一个记忆化的回调(以防止不需要的渲染):

import doSomething from "./doSomething";
const FrequentlyRerenders = ({ id }) => {
  const onEvent = useCallback(() => doSomething(id), [id]);
  return (
    <ExpensiveComponent onEvent={ onEvent } />
  );
};

但是如果我使用地图呢?例如:

import doSomething from "./doSomething";
const FrequentlyRerendersMap = ({ ids }) => {
  return ids.map(id => {
    const onEvent = useCallback(() => doSomething(id), [id]);
    return (
      <ExpensiveComponent key={id} onEvent={ onEvent } />
    );
  });
};

我应该如何正确使用useCallback?以上是传递多个回调的正确方法吗?它真的有效并且知道根据数组的一项来记忆每个回调吗?

4

3 回答 3

12

将返回的 JSX 转换成组件,然后就可以毫无问题地使用Callback

import doSomething from "./doSomething";
const MappedComponent =(props) => {
   const onEvent = useCallback(() => doSomething(props.id), []);
   return (
      <ExpensiveComponent onEvent={ onEvent } />
   );
}

const FrequentlyRerendersMap = ({ ids }) => {
  return ids.map(id => {
    return <MappedComponent key={id} id={id} />
  });
};
于 2019-05-03T05:55:45.617 回答
-1

另一种选择:

import doSomething from "./doSomething";

const FrequentlyRerendersMap = ({ ids }) => {
  const onEvent = useCallback((id) => () => doSomething(id), []);

  return ids.map(id => {
    
    return (
      <ExpensiveComponent key={id} onEvent={ onEvent: onEvent(id) } />
    );
  });
};
于 2021-05-24T13:28:22.377 回答
-2

现在在文档中明确不鼓励这样做。 https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

旧答案

重新架构师的答案是回避 IMO 的问题。不过,我认为创建一个新组件可能是个好主意。

不过,要回答这个问题,您的代码:

import doSomething from "./doSomething";
const FrequentlyRerendersMap = ({ ids }) => {
  return ids.map(id => {
    const onEvent = useCallback(() => doSomething(id), [id]);
    return (
      <ExpensiveComponent key={id} onEvent={ onEvent } />
    );
  });
};

实际上是您想要在地图中记忆的内容。我不知道 useCallback 的实现,但它应该会增加很少的内存开销。一个stackFrame,以及他们为将数组简化为记忆函数的某种键所做的任何事情。

除非您使用大量元素进行某些工作,否则 EG 会响应虚拟化组件无限滚动,否则您实际上可以安全地使用 Callback 的方式。事实上,较小的内存开销可能比重新渲染所有这些组件要便宜得多。

于 2019-06-24T22:42:02.300 回答