我应该在何时使用此钩子时将每个道具用useCallback或useMemo包装起来?

时间:2019-03-23 04:45:32

标签: reactjs react-hooks

如果有功能组件,我现在应该使用react钩子吗?如果用useCallback包装用props传递的每个函数,用useMemo包装其他props值?

我的组件中还具有依赖于任何props值的自定义功能,我应该用useCallback包装它吗?

有什么好的方法来决定使用此钩子从组件中包装哪些prop或const值?

如果这可以提高性能,为什么不一直这样做呢?

让我们考虑在包装点击处理程序并添加自定义逻辑的自定义按钮

function ExampleCustomButton({ onClick }) {
  const handleClick = useCallback(
    (event) => {
      if (typeof onClick === 'function') {
        onClick(event);
      }

      // do custom stuff

    },
    [onClick]
  );

  return <Button onClick={handleClick} />;
}

让我们考虑自定义按钮,我们在其中包装点击处理程序并根据情况添加自定义逻辑

function ExampleCustomButton({ someBool }) {
  const handleClick = useCallback(
    (event) => {
      if (someBool) {
        // do custom stuff
      }
    },
    [someBool]
  );

  return <Button onClick={handleClick} />;
}

在这两种情况下,我应该用useCallback包装处理程序吗?

与使用备忘录类似的案例。

function ExampleCustomButton({ someBool }) {
  const memoizedSomeBool = useMemo(() => someBool, [someBool])
  const handleClick = useCallback(
    (event) => {
      if (memoizedSomeBool) {
        // do custom stuff
      }
    },
    [memoizedSomeBool]
  );

  return <Button onClick={handleClick} />;
}

在此示例中,我甚至将备注值传递给useCallback

另一种情况,如果在组件树中许多组件记忆相同的值呢?这对性能有何影响?

2 个答案:

答案 0 :(得分:5)

不值得,有多种原因:

  1. 甚至官方文档都说您仅应在必要时这样做。
  2. 请记住,过早的优化是万恶之源:)
  3. 这使DX(开发人员经验)更加糟糕:它很难阅读;更难写;难以重构。
  4. 在处理原语时(例如您的示例),记笔记要比不做花费更多的CPU能力。原始值没有引用的概念,因此没有任何要记住的内容。另一方面,备忘录本身(与其他任何钩子一样)确实需要一些微小的处理,没有什么是免费的。即使它很小,也比没有传递任何东西要多(与仅传递原始图元相比),因此您可以使用这种方法来射击自己的脚。

将所有钩子放在一起-键入所有的钩子比在用户将钩子放到应用程序中所花费的时间要多得多。遵循良好的旧规则:先测量,然后优化

答案 1 :(得分:2)

我同意@jalooc提出的原则

要提供有关OP中展示的用例的更多信息,这是我的建议:

昂贵的儿童渲染

function Component() {
  const callback = useCallback(() => { dostuff }, [deps])

  return <Child prop={callback} />
}

如果Child是要渲染的非常昂贵的组件,则上述内容有意义。因此,它可能是这样导出的:

function Child() { 
   ...this takes significant CPU... 
}

// Export as a pure component
export default React.memo(Child)

昂贵的计算

function Component({ foo }) {
  // This very expensive computation will only run when it's input (foo)
  // changes, allowing Component to re-render without performance issues
  const bar = useMemo(() => {
     ... something very complicated with `foo` ...
  }, [foo])

  return <div>{bar}</div>
}

结论

  1. 做有意义的事情或表现不好的事情
  2. 如果在渲染时发生变化的函数导致派生的计算昂贵,请记住它(useCallback)或将其移出范围。
  3. 如果组件本身的渲染成本很高,请在必要时借助React.memo使用#2使其纯净
  4. 如果重新计算本身很昂贵,请记住(useMemo
  5. 做有意义的事情或表现不好的事情