简体   繁体   English

我应该用useCallback或useMemo包装每个prop,何时使用这个钩子?

[英]Should I wrap every prop with useCallback or useMemo, when to use this hooks?

With react hooks now available should I in case of functional components wrap every function passed with props with useCallback and every other props value with useMemo ? 随着反应钩现已我应该在功能部件的情况下,包裹用的道具通过各项功能useCallback并与其他所有的道具价值useMemo

Also having custom function inside my component dependent on any props value should I wrap it with useCallback ? 我的组件内部的自定义函数依赖于任何道具值,我应该用useCallback包装吗?

What are good practices to decide which props or const values from component wrap with this hooks ? 使用此挂钩决定组件包装中的哪些props或const值有什么好的做法?

If this improves performance why not to do it at all times ? 如果这样可以提高性能,为什么不在任何时候都这样做呢?

Lets consider custom button where we wrap click handler and add custom logic 让我们考虑自定义按钮,我们包装点击处理程序并添加自定义逻辑

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

      // do custom stuff

    },
    [onClick]
  );

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

Lets consider custom button where we wrap click handler and add custom logic on condition 让我们考虑自定义按钮,我们包装点击处理程序并在条件下添加自定义逻辑

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

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

Should i in this two cases wrap my handler with useCallback ? 我应该在这两种情况下使用useCallback包装我的处理程序吗?

Similar case with use memo. 使用备忘录的类似情况。

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

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

In this example I even pass memoized value to useCallback . 在这个例子中,我甚至将memoized值传递给useCallback

Another case what if in the component tree many components memoize same value ? 另一种情况是,如果在组件树中许多组件记忆相同的值? How does this impact performance ? 这对性能有何影响?

Not worth it, for multiple reasons: 不值得,原因有多种:

  1. Even official docs say you should do it only when necessary. 甚至官方文件也说你应该只在必要时才这样做。
  2. Keep in mind that premature optimization is the root of all evil :) 请记住, 过早优化是所有邪恶的根源 :)
  3. It makes DX (developer experience) far worse: it's harder to read; 它使DX(开发者体验)更糟糕:它更难阅读; harder to write; 更难写; harder to refactor. 更难以重构。
  4. When dealing with primitives (like in your example) memoizing costs more CPU power than not doing it. 处理原语时(如在您的示例中),memoizing比不执行操作会花费更多的CPU功率。 A primitive value doesn't have a concept of references , so there's nothing to memoize in them. 原始值没有引用的概念,因此没有任何内容可以记忆。 On the other hand, memoization itself (as any other hook) does require some tiny processing, nothing is for free. 另一方面,memoization本身(与任何其他钩子一样) 确实需要一些微小的处理,没有什么是免费的。 Even though it's tiny, it's still more than nothing (compared to just passing a primitive through), so you'd shoot your own foot with this approach. 虽然它很小,但它仍然比什么都没有(相比之下只是传递一个原语),所以你用这种方法射击自己的脚。

To put all together - you'd waste more time typing all the hooks than a user would gain on having them in the application if you want to put them everywhere. 把所有的东西放在一起 - 如果你想把它们放在任何地方,你会浪费更多的时间来键入所有钩子,而不是用户在应用程序中获得它们。 The good old rule applies: Measure, then optimize . 适用的旧规则适用: 测量,然后优化

I agree with the principles proposed by @jalooc 我同意@jalooc提出的原则

To give some more insight about the exhibited use cases in the OP, here is my advice: 为了更好地了解OP中展示的用例,我的建议如下:

Expensive children renders 昂贵的孩子们呈现

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

  return <Child prop={callback} />
}

The above makes sense if Child is a very expensive component to render. 如果Child是一个非常昂贵的渲染组件,上述内容就有意义了。 As such, it is probably exported like so: 因此,它可能像这样导出:

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

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

Expensive computations 昂贵的计算

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>
}

Conclusion 结论

  1. Do what makes sense or that have measured bad performance 做有意义或有不良表现的事情
  2. If a function that changes at render causes derived expensive computations, memoize it ( useCallback ) or move it outside the scope if you can. 如果在渲染时更改的函数导致派生昂贵的计算,请useCallback它( useCallback )或将其移出范围外(如果可以)。
  3. If a component itself is expensive to render, make it pure with React.memo , with the help of #2 if necessary 如果组件本身的渲染成本很高,请使用React.memo使其纯净,必要时在#2的帮助下
  4. If something IS itself expensive to re-compute, memoize it ( useMemo ) 如果重新计算某些东西本身很昂贵,请useMemo它( useMemo
  5. Do what makes sense or that have measured bad performance 做有意义或有不良表现的事情

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM