React性能优化

1.shouldComponentUpdate

一个组件更新时,无论是设置了新的props/调用了setState方法/调用forceUpdate方法,React都会调用该组件所有子组件的render方法。在组件树深度嵌套或render方法十分复杂的页面上这可能会带来延迟。

组件的render方法有时候会在不必要的情况下被调用。如:在组件渲染过程中没有使用props或state值,或组件的props或state并没有在父组件重新渲染时发生改变时,重新渲染这个组件会得到和已存在的虚拟DOM结构一模一样的结构,这样的设计过程是没有必要的。

React提供的组件生命周期方法:shouldComponentUpdate可以帮助React正确地判断是否需要调用指定组件的render方法。

shouldComponentUpdate返回false即可以不调用组件的渲染方法,并使用之前渲染好的虚拟DOM;返回true则是让React调用组件的渲染方法并计算出新的虚拟DOM。默认返回true,因此组件总是会调用render方法。

在组件首次渲染时,shouldComponentUpdate方法不会被调用。

shouldComponentUpdate方法接收两个参数,即新的props和新的state,以帮助你决定是否重新渲染:

var SurveyEditor = React.createClass({

shouldComponentUpdate:function (nextProps, nextState) {

return nextProps.id !== this.props.id;

}

});

对于给定同样的props和state总是渲染出同样结果的组件,我们可以添加React.addons.PureRenderMixin插件来处理shouldComponentUpdate。

这个插件会重写shouldComponentUpdate方法,并在该方法内对新老props及state进行对比,如果发现它们完全一致则返回false,如上面的例子。

var EditEssayQuestion = React.createClass({

mixin: [React.addons.PureRenderMixin],

propTypes: {

key: React.PropTypes.number.isRequired,

onChange: React.PropTypes.func.isRequired,

onRemove: React.PropTypes.func.isRequired,

question: React.PropTypes.object.isRequired

},

render: function () {

var description = this.props.question.description || "";

return (

<EditQuestion type='essay' onRemove={this.handleRemove}>

<label>Description</label>

<input type='text' className='description' value={description} onChange={this.handleChange} />

</EditQuestion>

);

},

handleChange: function (ev) {

var question = merge(this.props.question, { description: ev.target.value });

this.props.onChange(this.props.key, question);

},

handleRemove: function () {

this.props.onRemove(this.props.key);

}

});

如果props或state结构较深或较复杂,对比的过程会比较缓慢。为减少这种情况带来的问题,可以考虑使用不可变的数据结构,比如:Immutable.js,或使用不可变性辅助插件。

2.不可变性辅助插件

在需要比较对象以确认是否更新时,使用不可变的数据结构能让shouldComponentUpdate方法变得更加简单。

可以使用React.addons.update来确保组件的不可变性。React.addons.update接受一个数据结构和一个配置对象。可以在配置对象中传入$slice、$push、$unshift、$set、$merge和$apply。

var React = require('react/addons');

var Divider = require('./divider');

var DraggableQuestions = require('./draggable_questions');

var SurveyForm = require('./survey_form');

var EditYesNoQuestion = require('./questions/edit_yes_no_question');

var EditMultipleChoiceQuestion = require('./questions/edit_multiple_choice_question');

var EditEssayQuestion = require('./questions/edit_essay_question');

var SurveyActions = require("../flux/SurveyActions");

var update = React.addons.update;

var ReactCSSTransitionGroup = React.addons.CSSTransitionGroup;

var SUPPORTED_QUESTIONS = {

yes_no: EditYesNoQuestion,

multiple_choice: EditMultipleChoiceQuestion,

essay: EditEssayQuestion

};

var SurveyEditor = React.createClass({

getInitialState: function () {

return {

dropZoneEntered: false,

title: '',

introduction: '',

questions: []

};

},

render: function () {

var questions = this.state.questions.map(function (q, i) {

return SUPPORTED_QUESTIONS[q.type]({

key: i,

onChange: this.handleQuestionChange,

onRemove: this.handleQuestionRemove,

question: q

});

}.bind(this));

var dropZoneEntered = '';

if (this.state.dropZoneEntered) {

dropZoneEntered = 'drag-enter';

}

return (

<div className='survey-editor'>

<div className='row'>

<aside className='sidebar col-md-3'>

<h2>Modules</h2>

<DraggableQuestions />

</aside>

<div className='survey-canvas col-md-9'>

<SurveyForm

title={this.state.title}

introduction={this.state.introduction}

onChange={this.handleFormChange}

/>

<Divider>Questions</Divider>

<ReactCSSTransitionGroup transitionName='question'>

{questions}

</ReactCSSTransitionGroup>

<div

className={'drop-zone well well-drop-zone ' + dropZoneEntered}

onDragOver={this.handleDragOver}

onDragEnter={this.handleDragEnter}

onDragLeave={this.handleDragLeave}

onDrop={this.handleDrop}

>

Drag and drop a module from the left

</div>

<div className='actions'>

<button className="btn btn-lg btn-primary btn-save" onClick={this.handleSaveClicked}>Save</button>

</div>

</div>

</div>

</div>

);

},

handleFormChange: function (formData) {

this.setState(formData);

},

handleDragOver: function (ev) {

// This allows handleDropZoneDrop to be called

// https://code.google.com/p/chromium/issues/detail?id=168387

ev.preventDefault();

},

handleDragEnter: function () {

this.setState({dropZoneEntered: true});

},

handleDragLeave: function () {

this.setState({dropZoneEntered: false});

},

handleDrop: function (ev) {

var questionType = ev.dataTransfer.getData('questionType');

var questions = update(this.state.questions, {

$push: [{ type: questionType }]

});

this.setState({

questions: questions,

dropZoneEntered: false

});

},

handleQuestionChange: function (key, newQuestion) {

var questions = update(this.state.questions, {

$splice: [[key, 1, newQuestion]]

});

this.setState({ questions: questions });

},

handleQuestionRemove: function (key) {

var questions = update(this.state.questions, {

$splice: [[key, 1]]

});

this.setState({ questions: questions });

},

handleSaveClicked: function (ev) {

SurveyActions.save({

title: this.state.title,

introduction: this.state.introduction,

questions: this.state.questions

});

}

});

    3.深入调查拖慢应用的部分

React.addons.Perf插件能找到添加shouldComponentUpdate的最佳位置。

首先在Chrome控制台中运行React.addons.Perf.start();该命令会启动采集快照。

然后在页面操作后运行React.addons.Perf.stop();

最后再在控制台运行React.addons.Perf.printWaster();会输出列表,列表中包含组件和组件耗费时间。对于没有改变props和state的组件可以设置shouldComponentUpdate:function(){return false;}

  4.键(key)

列表中使用key属性。作用:给React提供一种除组件类之外的识别子组件的最小变化。

项目地址:https://github.com/backstopmedia/bleeding-edge-sample-app

参考书:《React引领未来的用户界面开发框架》

时间: 2024-10-07 13:48:28

React性能优化的相关文章

关于React性能优化

这几天陆陆续续看了一些关于React性能优化的博客,大部分提到的都是React 15.3新加入的PureComponent ,通过使用这个类来减少React的重复渲染,从而提升页面的性能.使用过React的朋友都知道,React组件只有在state和props发生改变时才会触发render,如果state和props没有发生改变,render就不执行.通常在写页面的时候,如果没有使用PureComponent类,为了避免重复渲染而产生的性能问题,我们会使用shouldComponentUpdat

React性能优化之PureComponent 和 memo使用分析

前言 关于react性能优化,在react 16这个版本,官方推出fiber,在框架层面优化了react性能上面的问题.由于这个太过于庞大,我们今天围绕子自组件更新策略,从两个及其微小的方面来谈react性能优化. 其主要目的就是防止不必要的子组件渲染更新. 子组件何时更新? 首先我们看个例子,父组件如下: import React,{Component} from 'react'; import ComponentSon from './components/ComponentSon'; im

React 性能优化总结

初学者对React可能满怀期待,觉得React可能完爆其它一切框架,甚至不切实际地认为React可能连原生的渲染都能完爆--对框架的狂热确实会出现这样的不切实际的期待.让我们来看看React的官方是怎么说的.React官方文档在Advanced Performanec这一节,这样写道: One of the first questions people ask when considering React for a project is whether their application wi

react性能优化要点

1.减少render方法的调用 1.1继承React.PureComponent(会自动在内部使用shouldComponentUpdate方法对state或props进行浅比较.)或在继承自React.Component类型的组件中使用shouldComponentUpdate方法来决定render方法是否被调用. 使用浅比较时,如果是对象类型就会出问题,因此最好是使用immutable类型.<immutable在性能优化中的作用> 1.2在调用组件时,如果某个属性值是函数,避免使用箭头函数

React性能优化相关

React渲染页面包括两个很重要的组成部分: 1.构建虚拟dom 2.根据虚拟dom变化渲染真实dom 对于第二部分来说,我们很难深入到React核心的diff算法等,因此主要从第一部分入手来优化性能. 针对第一部分,从优化角度来说,最直观想到的就是缩短构建虚拟dom的时间.具体到组件层面,就是减少无状态组件的函数执行以及类组件的render. 函数组件: hooks是专门针对函数组件来设计的模式,如果不使用hooks,函数组件便无法保存和管理自己的状态,直白一点理解就是函数每次执行的时候内部的

React组件性能优化

转自:https://segmentfault.com/a/1190000006100489 React: 一个用于构建用户界面的JAVASCRIPT库. React仅仅专注于UI层:它使用虚拟DOM技术,以保证它UI的高速渲染:它使用单向数据流,因此它数据绑定更加简单:那么它内部是如何保持简单高效的UI渲染呢? React不直接操作DOM,它在内存中维护一个快速响应的DOM描述,render方法返回一个DOM的描述,React能够计算出两个DOM描述的差异,然后更新浏览器中的DOM. 就是说R

react+redux渲染性能优化原理

大家都知道,react的一个痛点就是非父子关系的组件之间的通信,其官方文档对此也并不避讳: For communication between two components that don't have a parent-child relationship, you can set up your own global event system. Subscribe to events in componentDidMount(), unsubscribe in componentWillU

正式学习 React(三)番外篇 reactjs性能优化之shouldComponentUpdate

性能优化 每当开发者选择将React用在真实项目中时都会先问一个问题:使用react是否会让项目速度更快,更灵活,更容易维护.此外每次状态数据发生改变时都会进行重新渲染界面的处理做法会不会造成性能瓶颈?而在react内部则是通过使用一些精妙的技巧来最小化每次造成ui更新的昂贵的dom操作从而保证性能的. 避免直接作用于DOM react实现了一层虚拟dom,它用来映射浏览器的原生dom树.通过这一层虚拟的dom,可以让react避免直接操作dom,因为直接操作浏览器dom的速度要远低于操作Jav

React组件性能优化总结

性能优化的思路 影响网页性能最大的因素是浏览器的重排(repaint)和重绘(reflow). React的Virtual DOM就是尽可能地减少浏览器的重排和重绘. 从React渲染过程来看,如何防止不必要的渲染是解决问题的关键. 性能优化的具体办法 1. 尽量多使用无状态函数构建组件 无状态组件只有props和context两个参数.它不存在state,没有生命周期方法,组件本身即有状态组件构建方法中的render方法. 在合适的情况下,都应该必须使用无状态组件.无状态组件不会像React.