最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 你真的应该在React中使用 useMemo吗? 让我们一起来看看(译)

    正文概述 掘金(smallbone)   2021-02-26   501

    我们的一些开发人员最近提出了一个问题,什么时候我应该在 React 中使用 useMemo?这是一个非常好的问题。在本文中,我们将使用一种科学的方法,定义一个假设,并在 React 中使用现实生活中的基准对其进行测试。

    请继续阅读,了解 useMemo对性能的影响。

    什么是 useMemo?

    UseMemo是 React 提供的一个钩子。这个钩子允许开发人员根据依赖列表来缓存变量的值。如果此依赖列表中的任何变量发生更改,React 将重新运行此数据的处理进程并重新缓存它。如果依赖列表中的变量值之前已经缓存过,则 React 将从缓存中获取值。

    这对组件的重新渲染有重大影响。一旦组件重新渲染,它将从缓存中提取值,而不必一次又一次地循环一个数组或处理数据。

    React对于 useMemo 是如何描述的?

    如果我们看一下React 关于 useMemo的文档 ,它在应该何时使用它并没有被提及。他们只是简单地提到它的作用和使用方法。

    这里的问题是,从什么角度来看 useMemo是有趣的?在我们看到使用 useMemo的性能优势之前,数据应该有多复杂或多大?开发者应该何时使用 useMemo?

    假设

    在我们开始实验之前,让我们先做一个假设。

    让我们首先定义要执行的对象和处理的复杂度为 n。如果 n = 100,那么我们需要循环遍历一个由100个条目组成的数组,以获得 memo-ed 变量的最终值。

    然后,我们还需要将两个操作分开。第一个动作是组件的初始渲染。在这种情况下,如果一个变量使用 useMemo或不使用 useMemo,它们都必须计算初始值。一旦完成了第一次渲染,用 useMemo进行随后的重新渲染(我们需要测量的第二个操作)可以从缓存中检索值,与非memo版本相比,性能上的优势应该是可见的。

    在所有情况下,我预计在初始渲染期间会有大约5-10%的开销,以便去设置缓存并存储该值。当n<1000时,我希望看到useMemo的性能损失。对于n>1000的情况,我希望在使用useMemo重新渲染时看到类似或更好的性能,但由于额外的缓存算法,初始渲染仍然应该稍微慢一些。你的假设是什么?

    基准测试设置

    我们设置了一个小的 React 组件如下,它将生成一个复杂度为 n 的对象,复杂度定义为属性level。

    import React from 'react';
    const BenchmarkNormal = ({level}) => {
        const complexObject = {
            values: []
        };
        for (let i = 0; i <= level; i++) {
            complexObject.values.push({ 'mytest' });
        }
        return ( <div>Benchmark level: {level}</div>);
    };
    export default BenchmarkNormal;
    

    这是我们正常的基准组件,我们还将为 useMemo做一个基准组件 BenchmarkMemo。

    import React, {useMemo} from 'react';
    const BenchmarkMemo = ({level}) => {
        const complexObject = useMemo(() => {
            const result = {
                values: []
            };
            
            for (let i = 0; i <= level; i++) {
                result.values.push({'mytest'});
            };
            return result;
        }, [level]);
        return (<div>Benchmark with memo level: {level}</div>);
    };
    export default BenchmarkMemo;
    

    然后,我们在 App.js 中设置这些组件,以便在按下按钮时显示。我们还使用 React 的 来提供渲染时间。

    function App() {
        const [showBenchmarkNormal, setShowBenchmarkNormal] = useState(false);
        // Choose how many times this component needs to be rendered
        // We will then calculate the average render time for all of these renders
        const timesToRender = 10000;
        // Callback for our profiler
        const renderProfiler = (type) => {
            return (...args) => {
                // Keep our render time in an array
                // Later on, calculate the average time
                // store args[3] which is the render time ...
            };
        };
        // Render our component 
        return <p> {showBenchmarkNormal && [...Array(timesToRender)].map((index) => {
            return <Profiler id={`normal-${index}`} onRender={renderProfiler('normal')}>
                <BenchmarkNormal level={1} />
            </Profiler>;
        })}
        </p>;
    }
    

    如你所见,我们渲染组件10000次,并获取这些组件的平均渲染时间。现在我们需要一种机制来触发组件的按需重新渲染,同时不必重新计算 useMemo,因此我们不希望修改 useMemo的依赖列表中的任何值。

    // Add a simple counter in state
    // which can be used to trigger re-renders
    const [count, setCount] = useState(0);
    const triggerReRender = () => {
        setCount(count + 1);
    };
    // Update our Benchmark component to have this extra prop
    // Which will force a re-render
    <BenchmarkNormal level={1} count={count} />
    

    为了保持结果的清晰,我们总是在开始测试之前从一个新的浏览器页面开始(除了重新渲染) ,以清除任何可能仍然在页面上并影响我们的结果的缓存。

    结果

    复杂度 n = 1的结果

    你真的应该在React中使用 useMemo吗? 让我们一起来看看(译)

    你真的应该在React中使用 useMemo吗? 让我们一起来看看(译)

    复杂度在左列显示,第一个测试是初始渲染,第二个测试是第一次重新渲染,最后一个测试是第二次重新渲染。第二列显示了普通基准测试的结果,不使用useMemo。最后一列显示了使用 useMemo的基准测试的结果。这些值是我们的基准组件渲染时间超过10000次的平均值。

    当使用 useMemo时,初始渲染会慢19% ,这比预期的5-10% 要高得多。随后的渲染仍然很慢,因为通过 useMemo缓存的开销比重新计算实际值的开销更大。

    总之,对于复杂度 n = 1,不使用 useMemo总是更快,因为开销总是比性能增益更昂贵。

    复杂度 n = 100的结果

    你真的应该在React中使用 useMemo吗? 让我们一起来看看(译)

    你真的应该在React中使用 useMemo吗? 让我们一起来看看(译)

    在复杂度为100的情况下,使用useMemo的初始渲染变得慢了62%,这是一个显著的数字。随后的重新渲染似乎平均略快或类似。

    总之,复杂度为100的初始渲染显著地慢了,而随后的重新渲染相当类似,最多只是稍微快一点。在这一点上,useMemo似乎还没有什么意思。

    复杂度 n = 1000的结果

    你真的应该在React中使用 useMemo吗? 让我们一起来看看(译) 你真的应该在React中使用 useMemo吗? 让我们一起来看看(译)

    由于复杂度为1000,我们注意到使用 useMemo的初始渲染变慢了183% ,因为据推测,useMemo缓存正在更努力地存储值。随后的渲染速度大约快了37%!

    此时,我们可以看到重新渲染时的性能有一定的提升,但这并不是没有代价的。初始渲染的速度慢了很多,时间损失达183%。

    总之,在复杂度为1000的情况下,我们可以看到在初始渲染时性能损失更大(183%) ,然而,随后的渲染速度要快37% 。

    这是否已经很有趣,将高度依赖于你的用例。在初始渲染过程中损失183%的性能是很难卖的,但在组件中大量重新渲染的情况下可能是合理的。

    复杂度 n = 5000的结果

    你真的应该在React中使用 useMemo吗? 让我们一起来看看(译)

    你真的应该在React中使用 useMemo吗? 让我们一起来看看(译)

    在复杂度为5000的情况下,我们注意到使用useMemo的初始渲染速度要慢545% 。似乎数据和处理的复杂度越高,与不使用useMemo相比,使用useMemo的初始渲染速度越慢。

    有趣的部分是在看后续渲染时出现的。在这里,我们注意到,在每一次后续渲染中,使用useMemo的性能都有437%到609%的提升。

    总之,使用useMemo,初始渲染的成本要高很多,但后续的重渲染有更大的性能提升。如果你的应用程序的数据/处理复杂度>5000,并且需要重新渲染几次,我们可以看到使用useMemo的好处。

    结果说明

    友好的读者社区已经指出了一些可能的原因,比如为什么初始渲染会慢很多,比如运行生产模式等等。我们重新测试了所有的实验,发现结果是相似的。这些比率相似,但实际值可能更低。总的来说结论是一样的。

    总结

    你真的应该在React中使用 useMemo吗? 让我们一起来看看(译)

    这些是我们对复杂度为n的组件的结果,其中应用程序将循环并将值添加到一个数组n次。**请注意,结果会根据你处理数据的具体方式和数据量而变化。**不过,这应该能够让你了解不同大小的数据集的性能差异。

    是否应该使用 useMemo将在很大程度上取决于您的用例,但是对于复杂度小于100,useMemo似乎没什么意思。

    值得注意的是,useMemo最初的渲染在性能方面遭受了相当大的挫折。我们预计初始性能损失大约为5-10% ,但发现这在很大程度上取决于数据/处理的复杂性,甚至可能导致500% 的性能损失,这比预期的性能损失多100倍。

    我们已经重新运行了几次测试,甚至在得到结果之后,我们可以说后续的结果是非常一致的,类似于我们已经记录下来的最初结果。

    主要收获

    我们都同意,通过保持变量的同一对象引用,useMemo对于避免不必要的重新渲染是很有用的。

    对于使用 useMemo缓存实际计算的情况,其主要目标不是避免在子组件中重新渲染:

    • 当处理量很大时,应该使用 useMemo
    • 从什么时候 useMemo变得有趣以避免额外处理的阈值在很大程度上取决于您的应用程序
    • 在处理量很低的情况下使用useMemo,可能会有额外的使用开销。

    你什么时候使用 useMemo?这些发现会改变你何时使用 useMemo的想法吗?请在评论中告诉我们!

    原文链接: medium.com/swlh/should…


    起源地下载网 » 你真的应该在React中使用 useMemo吗? 让我们一起来看看(译)

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元