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,122);font-weight:bold;">onChange: React.PropTypes.func.isRequired,122);font-weight:bold;">onRemove: question: React.PropTypes.object.isRequired

},

render: function () {

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

return (

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

label>Description</input ='text' className='description' value={description} onChangehandleChange} />

EditQuestion>

);

},67);">handleChange: function (ev) {

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

onChange(key, question);

},67);">handleRemove: onRemove(key);

}

});

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


2.不可变性辅助插件

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

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

React = require('react/addons');

Divider = require('./divider');

DraggableQuestions = require('./draggable_questions');

SurveyForm = require('./survey_form');

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

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

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

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

update = React.addons.update;

ReactCSSTransitionGroup = React.addons.CSSTransitionGroup;

SUPPORTED_QUESTIONS = {

yes_no: EditYesNoQuestion,122);font-weight:bold;">multiple_choice: EditMultipleChoiceQuestion,122);font-weight:bold;">essay: EditEssayQuestion

};

SurveyEditor = React.createClass({

getInitialState: return {

dropZoneEntered: false,122);font-weight:bold;">title: '',122);font-weight:bold;">introduction: questions: []

};

},131);">questions = state.questions.map(function (q,i) {

return SUPPORTED_QUESTIONS[q.type]({

key: i,122);font-weight:bold;">onChange: handleQuestionChange,122);font-weight:bold;">onRemove: handleQuestionRemove,122);font-weight:bold;"> question: q

});

}.bind(this));

dropZoneEntered = '';

if (dropZoneEntered) {

'drag-enter';

}

div ='survey-editor'='row' aside ='sidebar col-md-3'h2>ModulesDraggableQuestions aside='survey-canvas col-md-9'SurveyForm

titlestate.title}

introductionintroduction}

handleFormChange}

Divider>QuestionsReactCSSTransitionGroup transitionName='question'>

{questions}

ReactCSSTransitionGroupdiv

'drop-zone well well-drop-zone ' + dropZoneEntered}

onDragOverhandleDragOver}

onDragEnterhandleDragEnter}

onDragLeavehandleDragLeave}

onDrophandleDrop}

>

Drag and drop a module from the left

div='actions'button ="btn btn-lg btn-primary btn-save" onClickhandleSaveClicked}>Savebutton>

);

},67);">handleFormChange: function (formData) {

this.setState(formData);

},67);">handleDragOver: function (ev) {

// This allows handleDropZoneDrop to be called

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

ev.preventDefault();

},67);">handleDragEnter: this.setState({true});

},67);">handleDragLeave: false});

},67);">handleDrop: questionType = ev.dataTransfer.getData('questionType');

questions = update(questions,{

$push: [{ type: questionType }]

});

this.setState({

questions: questions,128);font-weight:bold;">false

});

},67);">handleQuestionChange: function (key,newQuestion) {

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

});

this.setState({ questions });

},67);">handleQuestionRemove: function (key) {

1]]

});

handleSaveClicked: function (ev) {

SurveyActions.save({

state.title,122);font-weight:bold;">introduction,122);font-weight:bold;">questions: 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引领未来的用户界面开发框架》

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


react 中的高阶组件主要是对于 hooks 之前的类组件来说的,如果组件之中有复用的代码,需要重新创建一个父类,父类中存储公共代码,返回子类,同时把公用属性...
我们上一节了解了组件的更新机制,但是只是停留在表层上,例如我们的 setState 函数式同步执行的,我们的事件处理直接绑定在了 dom 元素上,这些都跟 re...
我们上一节了解了 react 的虚拟 dom 的格式,如何把虚拟 dom 转为真实 dom 进行挂载。其实函数是组件和类组件也是在这个基础上包裹了一层,一个是调...
react 本身提供了克隆组件的方法,但是平时开发中可能很少使用,可能是不了解。我公司的项目就没有使用,但是在很多三方库中都有使用。本小节我们来学习下如果使用该...
mobx 是一个简单可扩展的状态管理库,中文官网链接。小编在接触 react 就一直使用 mobx 库,上手简单不复杂。
我们在平常的开发中不可避免的会有很多列表渲染逻辑,在 pc 端可以使用分页进行渲染数限制,在移动端可以使用下拉加载更多。但是对于大量的列表渲染,特别像有实时数据...
本小节开始前,我们先答复下一个同学的问题。上一小节发布后,有小伙伴后台来信问到:‘小编你只讲了类组件中怎么使用 ref,那在函数式组件中怎么使用呢?’。确实我们...
上一小节我们了解了固定高度的滚动列表实现,因为是固定高度所以容器总高度和每个元素的 size、offset 很容易得到,这种场景也适合我们常见的大部分场景,例如...
上一小节我们处理了 setState 的批量更新机制,但是我们有两个遗漏点,一个是源码中的 setState 可以传入函数,同时 setState 可以传入第二...
我们知道 react 进行页面渲染或者刷新的时候,会从根节点到子节点全部执行一遍,即使子组件中没有状态的改变,也会执行。这就造成了性能不必要的浪费。之前我们了解...
在平时工作中的某些场景下,你可能想在整个组件树中传递数据,但却不想手动地通过 props 属性在每一层传递属性,contextAPI 应用而生。
楼主最近入职新单位了,恰好新单位使用的技术栈是 react,因为之前一直进行的是 vue2/vue3 和小程序开发,对于这些技术栈实现机制也有一些了解,最少面试...
我们上一节了了解了函数式组件和类组件的处理方式,本质就是处理基于 babel 处理后的 type 类型,最后还是要处理虚拟 dom。本小节我们学习下组件的更新机...
前面几节我们学习了解了 react 的渲染机制和生命周期,本节我们正式进入基本面试必考的核心地带 -- diff 算法,了解如何优化和复用 dom 操作的,还有...
我们在之前已经学习过 react 生命周期,但是在 16 版本中 will 类的生命周期进行了废除,虽然依然可以用,但是需要加上 UNSAFE 开头,表示是不安...
上一小节我们学习了 react 中类组件的优化方式,对于 hooks 为主流的函数式编程,react 也提供了优化方式 memo 方法,本小节我们来了解下它的用...
开源不易,感谢你的支持,❤ star me if you like concent ^_^
hel-micro,模块联邦sdk化,免构建、热更新、工具链无关的微模块方案 ,欢迎关注与了解
本文主题围绕concent的setup和react的五把钩子来展开,既然提到了setup就离不开composition api这个关键词,准确的说setup是由...
ReactsetState的执行是异步还是同步官方文档是这么说的setState()doesnotalwaysimmediatelyupdatethecomponent.Itmaybatchordefertheupdateuntillater.Thismakesreadingthis.staterightaftercallingsetState()apotentialpitfall.Instead,usecom