React-组件-性能优化

嵌套组件的 render 调用

  • 默认情况下, 只要父组件 render 被调用, 那么所有的后代组件的 render 也会被调用

当前存在的问题

  • 如果我们只修改了父组件的数据, 并没有修改子组件的数据, 并且子组件中也没有用到父组件中的数据
  • 那么子组件还是会重新渲染, 子组件的 render 方法还是会重新执行, 这样就带来了性能问题

App.js:

import React from "react";

class Home extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            age: 18
        }
    }
    render() {
        console.log('Home-render-被调用');
        return (
            <div>
                <p>{this.state.age}</p>
            </div>
        );
    }
}

class App extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            name: 'BNTang'
        }
    }

    render() {
        console.log('App-render-被调用');
        return (
            <div>
                <p>{this.state.name}</p>
                <button onClick={() => {
                    this.btnClick()
                }}>APP按钮
                </button>
                <Home/>
            </div>
        );
    }

    btnClick() {
        this.setState({
            name: 'Jonathan_Lee'
        });
    }
}

export default App;

image-20220504105917254

可以在 shouldcomponentupdate 该生命周期函数当中进行决定是否需要进行重新渲染,官方文档:https://zh-hans.reactjs.org/docs/react-component.html#shouldcomponentupdate

修改 App.js:

import React from "react";

class Home extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            age: 18
        }
    }

    shouldComponentUpdate(nextProps, nextState, nextContext) {
        return this.state.age !== nextState.age;
    }

    render() {
        console.log('Home-render-被调用');
        return (
            <div>
                <p>{this.state.age}</p>
            </div>
        );
    }
}

class App extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            name: 'BNTang'
        }
    }

    render() {
        console.log('App-render-被调用');
        return (
            <div>
                <p>{this.state.name}</p>
                <button onClick={() => {
                    this.btnClick()
                }}>APP按钮
                </button>
                <Home/>
            </div>
        );
    }

    btnClick() {
        this.setState({
            name: 'Jonathan_Lee'
        });
    }
}

export default App;

image-20220504105940625

shouldComponentUpdate 存在的问题

  • 所有需要优化的子组件都需要实现这个方法, 但这个方法并没有技术含量

解决方法

  • 让组件继承于 PureComponent, 让 React 自动帮我们实现

App.js:

import React from "react";

class Home extends React.PureComponent {
    constructor(props) {
        super(props);
        this.state = {
            age: 18
        }
    }

    render() {
        console.log('Home-render-被调用');
        return (
            <div>
                <p>{this.state.age}</p>
            </div>
        );
    }
}

class App extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            name: 'BNTang'
        }
    }

    render() {
        console.log('App-render-被调用');
        return (
            <div>
                <p>{this.state.name}</p>
                <button onClick={() => {
                    this.btnClick()
                }}>APP按钮
                </button>
                <Home/>
            </div>
        );
    }

    btnClick() {
        this.setState({
            name: 'Jonathan_Lee'
        });
    }
}

export default App;

image-20220504110616981

关于函数式组件的优化方案

对于函数式组件来说:

  • 没有继承关系
  • 没有生命周期方法

函数组件的性能优化

对于类组件, 我们可以通过实现 shouldComponentUpdate 方法, 或者继承于 PureComponent, 来解决性能的优化问题, 但是对于函数式组件, 是没有生命周期的, 是没有继承关系的,那么在函数式组件中如何解决性能优化问题呢?当然是有的,在 React 当中可以通过 React.memo() 高阶函数来定义函数式组件,React.memo() 会返回一个优化后的组件给我们。

App.js:

import React from "react";

const PurHome = React.memo(function () {
    console.log('Home-render-被调用');
    return (
        <div>
            <p>Home</p>
        </div>
    )
});

class App extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            name: 'BNTang'
        }
    }

    render() {
        console.log('App-render-被调用');
        return (
            <div>
                <p>{this.state.name}</p>
                <button onClick={() => {
                    this.btnClick()
                }}>APP按钮
                </button>
                <PurHome/>
            </div>
        )
    }

    btnClick() {
        this.setState({
            name: 'Jonathan_Lee'
        })
    }
}

export default App;

state 注意点

  • 永远不要直接修改 state 中的数据
  • 如果要修改 state 中的数据, 必须通过 setState 传递一个新的值

首先来看一个两种不同写法的运行结果吧,第一种就是直接进行修改不通过 setState 进行修改:

App.js:

import React from "react";

class App extends React.PureComponent {
    constructor(props) {
        super(props);
        this.state = {
            age: 0
        }
    }

    render() {
        console.log('App-render-被调用');
        return (
            <div>
                <p>{this.state.age}</p>
                <button onClick={() => {
                    this.btnClick()
                }}>APP按钮
                </button>
            </div>
        )
    }

    btnClick() {
        this.state.age = this.state.age + 1;
        this.setState(this.state);
    }
}

export default App;

运行如上代码会发现,页面没有进行重新渲染,就算继承了 PureComponent 也不会进行重新渲染,因为它的底层实现我们在如上的几个代码片段已经实现过了,就算比较当前的值是否和下一次的值是否不同如果不同就重新渲染但是,如上的这种设置方式就会造成两个值是相同的就不会再重新渲染页面。

第二种通过 setState 进行修改:

App.js:

import React from "react";

class App extends React.PureComponent {
    constructor(props) {
        super(props);
        this.state = {
            age: 0
        }
    }

    render() {
        console.log('App-render-被调用');
        return (
            <div>
                <p>{this.state.age}</p>
                <button onClick={() => {
                    this.btnClick()
                }}>APP按钮
                </button>
            </div>
        )
    }

    btnClick() {
        this.setState({
            age: this.state.age + 1
        });
    }
}

export default App;

如上之所以可以重新渲染是因为通过 setState 设置值就会触发 React 当中的重新渲染机制,在 PureComponent 底层实现比较的原理比较也是不同的两个值,也会触发页面的更新。

以上两种写法的区别:

  • 第一种这种方式是设置了以前的对象
  • 第二种方式是设置了一个新的对象
posted @ 2022-05-04 11:47  BNTang  阅读(79)  评论(0编辑  收藏  举报