美文网首页
在React中可以用来优化组件性能的方法

在React中可以用来优化组件性能的方法

作者: 马甲要掉了 | 来源:发表于2020-12-28 16:28 被阅读0次

    在React中可以用来优化组件性能的方法有:

    • 组件懒加载(React.lazy(...)和<Suspense />)
    • Pure Component
    • shouldComponentUpdate(...){...}生命周期函数
    • React.memo

    无用的渲染

    组件是构成React视图的一个基本单元。有些组件会有自己本地的状态(state,props), 当它们的值由于用户的操作而发生改变时,组件就会重新渲染。在一个React应用中,一个组件可能会被频繁地进行渲染。这些渲染虽然有一小部分是必须的,不过大多数都是无用的,它们的存在会大大降低我们应用的性能。
    eg:

    import React from 'react';
    
    class TestC extends React.Component {
        constructor(props) {
            super(props);
            this.state = {
                count: 0
            }
        }
        
        componentWillUpdate(nextProps, nextState) {
            console.log('componentWillUpdate')
        }
        
        componentDidUpdate(prevProps, prevState) {
            console.log('componentDidUpdate')
            
        }
        
        render() {
            return (
                <div >
                {this.state.count}
                <button onClick={()=>this.setState({count: 1})}>Click Me</button>
                </div>
            );
        }
    }
    export default TestC;
    

    TestC组件有一个本地状态count,它的初始值是0(state = {count: 0})。当我们点击Click Me按钮时,count的值被设置为1。这时候屏幕的数字将会由0变成1。当我们再次点击该按钮时,count的值还是1, 这时候TestC组件不应该被重新渲染,可是现实是这样的吗?
    为了测试count重复设置相同的值组件会不会被重新渲染, 我为TestC组件添加了两个生命周期函数: componentWillUpdate和componentDidUpdate。componentWillUpdate方法在组件将要被重新渲染时被调用,而componentDidUpdate方法会在组件成功重渲染后被调用。
    在浏览器中运行我们的代码,然后多次点击Click Me按钮,你可以看到以下输出:


    image.png

    我们可以看到'componentWillUpdate'和'componentWillUpdate'在每次我们点击完按钮后,都会在控制台输出来。所以即使count被设置相同的值,TestC组件还是会被重新渲染,这些就是所谓的无用渲染。

    shouldComponentUpdate

    为了避免React组件的无用渲染,我们可以实现自己的shouldComponentUpdate生命周期函数。
    当React想要渲染一个组件的时候,它将会调用这个组件的shouldComponentUpdate函数, 这个函数会告诉它是不是真的要渲染这个组件。
    如果我们的shouldComponentUpdate函数这样写:

    shouldComponentUpdate(nextProps, nextState) {
        return true        
    }
    

    复制代码其中各个参数的含义是:

    • nextProps: 组件将会接收的下一个参数props
    • nextProps: 组件的下一个状态state

    因为我们的shouldComponentUpdate函数一直返回true,这就告诉React,无论何种情况都要重新渲染该组件。
    可是如果我们这么写:

    shouldComponentUpdate(nextProps, nextState) {
        return false
    }
    

    因为这个方法的返回值是false,所以React永远都不会重新渲染我们的组件。

    因此当你想要React重新渲染你的组件的时候,就在这个方法中返回true,否则返回false。现在让我们用shouldComponentUpdate重写之前的TestC组件:

    import React from 'react';
    
    class TestC extends React.Component {
        constructor(props) {
            super(props);
            this.state = {
                count: 0
            }
        }
        
        componentWillUpdate(nextProps, nextState) {
            console.log('componentWillUpdate')
        }
        
        componentDidUpdate(prevProps, prevState) {
            console.log('componentDidUpdate')
        }
        
        shouldComponentUpdate(nextProps, nextState) {
            if (this.state.count === nextState.count) {
                return false
            }
            return true
        }
        
        render() {
            return ( 
                <div> 
                { this.state.count } 
                <button onClick = {
                    () => this.setState({ count: 1 }) }> Click Me </button> 
                </div>
            );
        }
    }
    
    export default TestC;
    

    我们在TestC组件里添加了shouldComponentUpdate方法,判断如果现在状态的count和下一个状态的count一样时,我们返回false,这样React将不会进行组件的重新渲染,反之,如果它们两个的值不一样,就返回true,这样组件将会重新进行渲染。
    再次在浏览器中测试我们的组件,刚开始的界面是这样的:


    image.png

    这时候,就算我们多次点击Click Me按钮,也只能看到两行输出:

    componentWillUpdate
    componentDidUpdate 
    

    Pure Component

    React在进行组件更新时,如果发现这个组件是一个PureComponent,它会将组件现在的state和props和其下一个state和props进行浅比较,如果它们的值没有变化,就不会进行更新。要想让你的组件成为Pure Component,只需要extends React.PureComponent即可。
    让我们用PureComponent去改写一下我们的代码吧:

    import React from 'react';
    
    class TestC extends React.PureComponent {
        constructor(props) {
            super(props);
            this.state = {
                count: 0
            }
        }
        
        componentWillUpdate(nextProps, nextState) {
            console.log('componentWillUpdate')
        }
        
        componentDidUpdate(prevProps, prevState) {
            console.log('componentDidUpdate')
        }
        
        /*shouldComponentUpdate(nextProps, nextState) {
            if (this.state.count === nextState.count) {
                return false
            }
            return true
        }*/
        
        render() {
            return ( 
                <div> 
                { this.state.count } 
                <button onClick = {
                    () => this.setState({ count: 1 })
                }> Click Me </button> 
                </div >
            );
        }
    }
    
    export default TestC;
    

    在上面的代码中,我将shouldComponentUpdate的代码注释掉了,因为React.PureComponent本身就帮我们实现了一样的功能。
    我们的component只在state由0变为1时被重新渲染了,后面都没有进行渲染。

    函数组件

    上面我们探讨了如何使用PureComponent和shouldComponentUpdate的方法优化类组件的性能。虽然类组件是React应用的主要组成部分,不过函数组件(Functional Component)同样可以被作为React组件使用。
    对于函数组件,它们没有诸如state的东西去保存它们本地的状态(虽然在React Hooks中函数组件可以使用useState去使用状态), 所以我们不能像在类组件中使用shouldComponentUpdate等生命函数去控制函数组件的重渲染。当然,我们也不能使用extends React.PureComponent了,因为它压根就不是一个类。

    使用React.memo()

    它的作用和React.PureComponent类似,是用来控制函数组件的重新渲染的。React.memo(...) 其实就是函数组件的React.PureComponent。

    如何使用React.memo(...)?

    我们只需将上面的Funcomponent作为参数传入React.memo中:

    const Funcomponent = ()=> {
        return (
            <div>
                Hiya!! I am a Funtional component
            </div>
        )
    }
    const MemodFuncComponent = React.memo(FunComponent)
    

    React.memo会返回一个纯化(purified)的组件MemoFuncComponent,这个组件将会在JSX标记中渲染出来。当组件的参数props和状态state发生改变时,React将会检查前一个状态和参数是否和下一个状态和参数是否相同,如果相同,组件将不会被渲染,如果不同,组件将会被重新渲染。
    在我们之前那个没用到React.memo(...)的例子中,count的重复设置会使组件进行重新渲染。可是我们用了React.memo后,该组件在传入的值不变的前提下是不会被重新渲染的。

    结论

    以下是几点总结:

    • React.PureComponent是银
    • React.memo(...)是金
    • React.PureComponent是给ES6的类组件使用的
    • React.memo(...)是给函数组件使用的
    • React.PureComponent减少ES6的类组件的无用渲染
    • React.memo(...)减少函数组件的无用渲染
    • 为函数组件提供优化是一个巨大的进步

    相关文章

      网友评论

          本文标题:在React中可以用来优化组件性能的方法

          本文链接:https://www.haomeiwen.com/subject/tuhtoktx.html