美文网首页
【React】—组件性能优化

【React】—组件性能优化

作者: 南慕瑶 | 来源:发表于2018-01-16 15:16 被阅读0次

一、优化原理

改写react生命周期shouldComponentUpdate,使其在需要重新渲染当前组件时返回true,否则返回false。不再全部返回true。

二、主流优化方式

1.react官方解决方案

原理:重写默认的shouldComponentUpdate,将旧props、state与新props、state逐个进行浅比较(形如:this.props.option === nextProps.option ?  false : true),如果全部相同,返回false,如果有不同,返回true。

PureRenderMixin(es5):

var PureRenderMixin = require('react-addons-pure-render-mixin');

    React.createClass({

    mixins: [PureRenderMixin],

    render: function() {

         return <div className={this.props.className}>foo</div>;

    }

});

Shallow Compare (es6):

var shallowCompare = require('react-addons-shallow-compare');

export class SampleComponent extends React.Component {

    shouldComponentUpdate(nextProps, nextState) {

        return shallowCompare(this, nextProps, nextState);

    }

    render() {

        return <div className={this.props.className}>foo</div>
    }

}

es7装饰器的写法:

import pureRender from "pure-render-decorator"

...

@pureRender

class SampleComponent extends Component {

    render() {

        return (

            <div className={this.props.className}>foo</div>

        )

    }

}

react 15.3.0+写法(用来替换react-addons-pure-render-mixin):

class SampleComponent extends React.PureComponent{

    render(){

        return(

            <div className={this.props.className}>foo</div>

        )

    }

}

*上述方案存在问题(浅比较的问题):

(1)某些props、state值未改变的情况,返回true,例如:

 <Cell options={this.props.options || [ ]} />

当this.props.options == false时,options=[ ]。当父组件两次渲染,this.props.options一直 == false,对于Cell组件来说,options没有改变,不需要重新渲染。但Cell的shouldComponentUpdate中进行的是浅比较,由于[ ] !== [ ],所以,this.props.options === nextProps.options为false,shouldComponentUpdate会返回true,Cell将进行重新渲染。

解决方法如下:

const default = [ ];

<Cell options={this.props.options || default} />

(2)某些props、state值改变的情况,返回false,例如:

handleClick() {

    let {items} = this.state;

    items.push('new-item') ;

    this.setState({ items });

}

render() {

    return (

        <div>

            <button onClick={this.handleClick} />

            <ItemList items={this.state.items} />

        </div>
    )

}

如果ItemList是纯组件(PureComponent),那么这时它是不会被渲染的。因为尽管this.state.items的值发生了改变,但是它仍然指向同一个对象的引用。



2.Immutable

原理:Persistent Data Structure(持久化数据结构),也就是使用旧数据创建新数据时,要保证旧数据同时可用且不变。

Immutable Data就是一旦被创建,就不能再更改的数据。对 Immutable 对象的任何修改或添加删除操作都会返回一个新的 Immutable 对象。同时,为了避免 deepCopy 把所有节点都复制一遍带来的性能损耗,Immutable 使用了 Structural Sharing(结构共享),即如果对象树中一个节点发生变化,只修改这个节点和受它影响的父节点,其它节点则进行共享。

【在react中使用immutable】

改变shouldComponentUpdate的重新渲染规则

(1)防止每次setState或传递props,即使state和props的值没有发生改变也重新渲染组件,带来无谓的性能消耗

(2)防止浅比较带来的比较误差问题,以及深比较带来的性能消耗问题。

import { is, fromJS } from 'immutable';

constructor(){

    this.state = {

        person: fromJS({

                name: 'xuxuan',

                age: 12 

        });

   }

}

componentDidMount(){

    this.setState({

        person: this.state.person.update('name', v => v + 'update')

    });

}

shouldComponentUpdate: (nextProps, nextState) => {

    return !(this.props === nextProps || is(this.props, nextProps))

                ||

              !(this.state === nextState || is(this.state, nextState));

}

!!注意】state 本身必须是普通对象,但是里面的值可以是 immutable 的数据。

this.state和nextState是两个普通对象,通过is方法判断二者的值是否相同。

从setState到re-render整个过程(个人理解)

(1)setState中设置person的name值,由于person是immutable的,因此,这里会开辟一块新的内存,存储设置后的name(即使name的值没有真的发生改变,只要对immutable数据进行了设置操作,就会生成一个全新的对象),同时,开辟新内存,存储受name影响的immutable的各级父节点,这里只有person。而,其余未受影响的节点,将进行内存共享,如这里的age。由此,形成了新的state对象,即:nextState。

(2)setState(nextState)操作触发shouldComponentUpdate生命周期执行。

(3)shouldComponentUpdate中使用immutable.js的is方法对比两个对象。

        这里,is采用hashCodevalueOf对比两个对象是否相同:

        *当对象的值没有改变,is返回true,组件不重新渲染。依然存储旧的state(nextState大概会被销毁吧)

        *当对象的值发生改变,is返回false,组件重新渲染。nextState替换state(state就不能再访问了,但它的immutable的属性应该还可以)

(4)当需要重新渲染的时候,对于state来说,就是用新的nextState替换旧的state。由于state是普通对象,因此可以被更改,被替换。

【关于is方法】

Immutable的is比较的是这个对象hashCodevalueOf,只要两个对象的hashCode相等,值就是相同的,避免了深度遍历,提高了性能。

扩展:

hashCode的比较是将两个对象String化(eg:{a:111} —> '{a:111}')后,比较两个字符串对应位置字符的charCode是否相同,完全相同则认为是两个相同的对象。

使用 Immutable 后,如下图,当红色节点的 state 属性值变化后,

Immutable数据树结构变化示意图

【注】

整棵树就是一个Immutable的对象。

当红色节点发生改变,为这个节点及其父节点开辟新的内存,存储新数据,其他蓝色节点不变,共享之前的内存。

immutable.js框架是非常好的Immutable库,其他可用api,详见官方文档。

使用原则:

由于侵入性较强,新项目引入比较容易,老项目迁移需要谨慎评估迁移成本。对于一些提供给外部使用的公共组件,最好不要把Immutable对象直接暴露在对外的接口中。

【!!Mark】

个人理解部分,如有理解偏差,请指正,感谢。

相关文章

  • 【React.js 20】React性能优化

    React性能优化 React性能优化主要分三块: React 组件性能优化 属性传递优化针对单组件性能优化,很多...

  • 深入浅出React和Redux学习笔记(五)

    React组建的性能优化 性能优化的方法: 单个React组件的性能优化; 多个React组件的性能优化; 利用r...

  • Redux源码剖析

    前面写了《React组件性能优化》《Redux性能优化》《React-Redux性能优化》,但是都没有从这些框架的...

  • React 组件性能优化

    React 组件性能优化最佳实践 React 组件性能优化的核心是减少渲染真实 DOM 节点的频率,减少 Virt...

  • React-Redux性能优化

    前面写了两篇文章《React组件性能优化》《Redux性能优化》,分别针对React和Redux在使用上的性能优化...

  • 组件的性能优化 - 01.单组件性能优化

    组件的性能优化 - 01.单组件性能优化 本文主要关注在React组件的性能优化的相关知识和原理上,便于对Reac...

  • 05|React组件的性能优化

    本文主要是针对性能优化做介绍,对应的React本身性能就比较不错!要介绍的点如下: 单个React组件的性能优化 ...

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

    在React中可以用来优化组件性能的方法有: 组件懒加载(React.lazy(...)和 ) Pure Comp...

  • 常见面试题总结(二)

    immutable如何优化react项目性能 react组件接收新的state和props之后默认会发生渲染,即使...

  • 疑问汇总

    1. react context是怎样实现 跨组件通信的? 从Context源码实现谈React性能优化[http...

网友评论

      本文标题:【React】—组件性能优化

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