【问题标题】:is useCallback a performance boost for the react app?useCallback 是 React 应用程序的性能提升吗?
【发布时间】:2021-07-21 18:48:16
【问题描述】:

有人可以向我解释一下useMemouseCallback 的使用是贵还是便宜?我检查了 React 的源代码,我认为它们使用起来很便宜,但我也读过一些人说它们不是。

在 Next.js 上下文中使用 useCallback:

const MyComp = () => {
  const router = useRouter():
  const handleClick = useCallback(() => router.push('/some-path'), [router]);
  return <button onClick={handleClick} />
}

这里是简单的箭头函数:

const MyComp = () => {
  const router = useRouter():
  return <button onClick={() => router.push('/some-path')} />
}

我是否使用useCallback 保存重新渲染? memoize和比较依赖数组[router]的开销,是不是比较贵?

附加信息:检查 React 的代码我看到他们使用 Object.is 而不是 ===== 比较 deps 数组项。

有人知道为什么吗?

同时检查这个组件的渲染:

import {useCallback, useState} from "react";

let i = 0

const CallbackDemo = () => {
    const [value, setValue] = useState('');
    console.log('render', i++);
    const handleClick = useCallback(() => setValue(Math.random()), []);
    return (
      <div>
        <span>{value}</span>
        <button onClick={handleClick}>New set</button>
      </div>
    );
}

export default CallbackDemo;

我看到使用或不使用 useCallback 的渲染数量相同

【问题讨论】:

  • 您可以阅读docs 了解Object.is=== 之间的区别。 this blog 谈到何时使用 useMemouseCallback 以及何时不使用。

标签: reactjs


【解决方案1】:

useCallback 像 useMemo 确实提高了性能 但!!!您不需要将它用于所有内容,因为它会使您的网站变慢。 这对于图表之类的繁重组件更好。 这会消耗大量资源并花费大量时间来处理,这将使该特定组件的加载速度更快,并且不会在您每次进行更改时卡住。

你可以看到像这样的深度压缩:

react useEffect comparing objects

此链接将向您展示如何进行深度压缩以获得使用效果

【讨论】:

    【解决方案2】:

    我是否使用useCallback 保存重新渲染?

    不是在那种特定情况下,不。 useCallback 代码确实可以让您大致节省赋值语句的成本,因为它不必更新 button 元素上的单击处理程序,但会以函数调用和遍历依赖关系数组为代价对于差异。所以在那种特定的情况下,它可能不值得这样做。

    如果您有一个更复杂的子组件,并且该组件被优化为在使用相同的道具调用时不会重新渲染(例如,通过 React.memoReact.PureComponent 或类似的),或者您正在传递函数到一堆子组件,那么您可能会通过不重新渲染它们来获得一些性能改进。

    考虑这个例子,simpleClickHandler 总是被重新创建,但memoizedClickHandler 通过useCallback 被重用¹:

    const { useState, useCallback } = React;
    
    const Parent = () => {
        const [counter, setCounter] = useState(0);
        console.log("Parent called");
    
        const simpleClickHandler = () => {
            console.log("Click occurred");
            setCounter(c => c + 1);
        };
        const memoizedClickHandler = useCallback(() => {
            console.log("Click occurred");
            setCounter(c => c + 1);
        }, []);
        
        return (
            <div>
                Count: {counter}
                <Child onClick={simpleClickHandler} handlerName="simpleClickHandler">simpleClickHandler</Child>
                <Child onClick={memoizedClickHandler} handlerName="memoizedClickHandler">memoizedClickHandler</Child>
            </div>
        );
    };
    
    const Child = React.memo(({handlerName, onClick, children}) => {
        console.log(`Child using ${handlerName} called`);
        return (
            <div onClick={onClick}>{children}</div>
        );
    });
    
    ReactDOM.render(<Parent/>, document.getElementById("root"));
    <div id="root"><?div>
    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>

    注意当你点击的时候,只有被传递给simpleClickHandler的孩子会重新渲染,而不是被传递给memoizedClickHandler的那个,因为memoizedClickHandler的值是稳定的,但是simpleClickHandler的值每次都会改变。

    使用useCallback 需要在父组件中进行更多工作(检查是否可以重用之前的函数),但可能有助于节省子组件中的工作。

    请务必注意,useCallback(和useMemo)为您提供的稳定性仅适用于性能原因,而不是正确性。如果需要,React 可以丢弃处理程序的先前副本并新建一个新副本,即使 deps 没有更改。如果你需要 正确性 保证(结果肯定 100% 不会改变,除非 deps 改变),你有使用 ref.但这是一个非常罕见的用例。

    附加信息:检查 React 的代码我看到他们使用 Object.is 而不是 ===== 比较 deps 数组项。

    有人知道为什么吗?

    主要是因为NaN === NaNfalse,因为与NaN所有 比较都是false。所以如果他们使用===,任何包含NaN 的deps 数组都会被认为与前一个不同。但是使用Object.is 可以避免这个问题,因为Object.is(NaN, NaN)true


    ¹ 请注意,这里的“重用”意味着:每次创建一个新的处理程序,就像 simpleClickHandler,但 useCallback 可能会返回您之前提供的处理程序,如果 deps没有改变,所以新的被扔掉了。 (JavaScript 引擎在分配和回收短期对象方面非常迅速。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-02
      • 1970-01-01
      • 2021-07-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多