详解在React.js中使用PureComponent的重要性和使用方式


Posted in Javascript onJuly 10, 2018

一、介绍PureComponent

React 15.3在2016.06.29发布了,这个版本最值得关注的是支持了 React.PureComponent ,它取代了之前的 pure-render-mixin 。在本文中,我们将讨论 PureComponent 的重要性和使用场景。

React.PureComponent最重要的一个用处就是优化React应用,这很容易快速地实现。使用 React.PureComponent 对性能的提升是非常可观的,因为它减少了应用中的渲染次数。

详解在React.js中使用PureComponent的重要性和使用方式

PureComponent改变了生命周期方法 shouldComponentupdate ,并且它会自动检查组件是否需要重新渲染。这时,只有PureComponent检测到 state 或者 props 发生变化时,PureComponent才会调用 render 方法,因此,你不用手动写额外的检查,就可以在很多组件中改变 state , 例如:

if (this.state.someVal !== computedVal) {
 this.setState({ someVal: computedVal })
}

根据React源码,如果组件是纯组件(Pure Component),那么一下比较是很容易理解的:

if (this._compositeType === CompositeTypes.PureClass) {
 shouldUpdate = !shallowEqual(prevProps, nextProps) || ! shallowEqual(inst.state, nextState);
}

其中, shadowEqual 只会"浅"检查组件的 props state ,这就意味着嵌套对象和数组是不会被比较的。

深比较操作是非常昂贵的,同时,如果这个组件还是纯组件(PureComponent),那么深比较将会更浪费。另外,你也可以使用 shouldComponentUpdate 来手动确定组件是否需要重新渲染。最简单的方式就是直接比较 props state :

shouldComponentUpdate(nextProps, nextState) {
 return nextProps.user.id === props.user.id;
}

除此之外,你可以使用 immutable 属性。这种情况下,属性的比较是非常容易的,因为已存在的对象不会发生改变,取而代之的是重新创建新的对象。其中, Immutable.js 就是非常好的Immutable库。

二、使用PureComponent

PureComponent节约了我们的时间,避免了多余的代码。那么,掌握如何正确使用它是非常重要的,否则如果使用不当,它就无法发挥作用。因为PureComponent仅仅是浅比较(shadow comparison),所以改变组件内部的 props 或者 state ,它将不会发挥作用。例如,让我们想想这样一种情况,父组件有一个render方法和一个click处理方法:

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 的值发生了改变,但是它仍然指向同一个对象的引用。但是,通过移除可变对象就很容易改变这种情况,使之能够正确被渲染。

handleClick() {
 this.setState(prevState => ({
  words: prevState.items.concat(['new-item'])
 }));
}

如果一个纯组件(PureComponent)的 state 或 props 引用了一个新对象,那么这个组件就会被重新渲染(re-render)。这暗示着,如果不想损失PureComponent的优点,那么我们应该避免以下的结构:

<Entity values={this.props.values || []}/>

如上面代码,新数组,即便是空数组,总是会迫使组件重新渲染。为了避免这个问题,你可以使用 defaultProps ,它包含了一个属性的初始化空状态。解决这个问题的另一种方法如下:

<CustomInput onChange={e => this.props.update(e.target.value)} />

在纯组件(PureComponent)被创建时,因为函数的新对象被创建了,所以它会获得新数据,并且重新渲染。解决这个问题最简单的方法就是: 在组件的 constructor 方法中使用 bind 。

constructor(props) {
  super(props)
  this.update = this.update.bind(this)
}
update(e) {
  this.props.update(e.target.value)
}
render() {
  return <MyInput onChange={this.update} />
}

同时,在JSX中,任何包含子元素(child elements)的组件, shallowEqual 检查总会返回false。

请谨记:纯组件忽略重新渲染时,不仅会影响它本身,而且会影响它的说有子元素,所以,使用PureComponent的最佳情况就是展示组件,它既没有子组件,也没有依赖应用的全局状态。

三、总结

事实上,如果你已经意识到 shallowEqual JS References 的特性,过渡到PureComponent是相当容易的。正常情况下,迁移的方式非常简单,就像改变组件继承的基类,从

class MyComponent extends Component {...}

class MyComponent extends PureComponent {...}

这样不仅能平滑过渡,甚至可以提升性能。所以,我极力推荐所有人在开发应用中使用PureComponent。

四、注意

在纯组件有子组件的时候,所有基于 this.context 改变的子组件,在 this.context 改变时, 将不会重新渲染 ,除非在父组件(Parent ParentComponent)中声明 contextTypes 。

本文翻译至habrahabr。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
jquery获取自定义属性(attr和prop)实例介绍
Apr 21 Javascript
js Array对象的扩展函数代码
Apr 24 Javascript
使用jquery实现简单的ajax
Jul 08 Javascript
解析Javascript小括号“()”的多义性
Dec 03 Javascript
JavaScript数据结构与算法之栈与队列
Jan 29 Javascript
JS动态改变浏览器标题的方法
Apr 06 Javascript
微信小程序 form组件详解
Oct 25 Javascript
在vue项目中引入高德地图及其UI组件的方法
Sep 04 Javascript
Node批量爬取头条视频并保存方法
Sep 20 Javascript
详解在create-react-app使用less与antd按需加载
Dec 06 Javascript
如何使用CSS3+JQuery实现悬浮墙式菜单
Jun 18 jQuery
JavaScript文档加载模式以及元素获取
Jul 28 Javascript
echarts整合多个类似option的方法实例
Jul 10 #Javascript
详解使用Next.js构建服务端渲染应用
Jul 10 #Javascript
node.js中TCP Socket多进程间的消息推送示例详解
Jul 10 #Javascript
vue中$set的使用(结合在实际应用中遇到的坑)
Jul 10 #Javascript
JavaScript中 ES6变量的结构赋值
Jul 10 #Javascript
vue超时计算的组件实例代码
Jul 09 #Javascript
微信小程序自定义底部弹出框
Nov 16 #Javascript
You might like
PHP使用json_encode函数时不转义中文的解决方法
2014/11/12 PHP
大家在抢红包,程序员在研究红包算法
2015/08/31 PHP
ECshop 迁移到 PHP7版本时遇到的兼容性问题
2016/02/15 PHP
PHP的Yii框架中使用数据库的配置和SQL操作实例教程
2016/03/17 PHP
DEDE实现转跳属性文档在模板上调用出转跳地址
2016/11/04 PHP
PHP多进程编程之僵尸进程问题的理解
2017/10/15 PHP
CI框架网页缓存简单用法分析
2018/12/26 PHP
javascript之水平横向滚动歌词同步的应用
2007/05/07 Javascript
jQuery ajax dataType值为text json探索分享
2013/09/23 Javascript
js实现jquery的offset()方法实例
2015/01/10 Javascript
jquery的幻灯片图片切换效果代码分享
2015/09/07 Javascript
全面解析JavaScript中“&amp;&amp;”和“||”操作符(总结篇)
2016/07/18 Javascript
原生JS实现风箱式demo,并封装了一个运动框架(实例代码)
2016/07/22 Javascript
AngularJS基础 ng-class-odd 指令示例
2016/08/01 Javascript
Nodejs基于LRU算法实现的缓存处理操作示例
2017/03/17 NodeJs
使用classList来实现两个按钮样式的切换方法
2018/01/24 Javascript
Bootstrap实现省市区三级联动(亲测可用)
2019/07/26 Javascript
python开发之for循环操作实例详解
2015/11/12 Python
python常用函数详解
2016/09/13 Python
Python实现的读取文件内容并写入其他文件操作示例
2019/04/09 Python
Python+selenium点击网页上指定坐标的实例
2019/07/05 Python
将python运行结果保存至本地文件中的示例讲解
2019/07/11 Python
树莓派4B+opencv4+python 打开摄像头的实现方法
2019/10/18 Python
Python timer定时器两种常用方法解析
2020/01/20 Python
使用pycharm和pylint检查python代码规范操作
2020/06/09 Python
tensorflow图像裁剪进行数据增强操作
2020/06/30 Python
泰国折扣酒店预订:Hotels2Thailand
2018/03/20 全球购物
Ryderwear美国官网:澳大利亚高端健身训练装备品牌
2018/04/24 全球购物
电大自我鉴定
2013/10/27 职场文书
机械专业毕业生推荐信范文
2013/11/25 职场文书
给实习单位的感谢信
2014/02/01 职场文书
成绩单家长评语大全
2014/04/16 职场文书
教师遵守党的政治纪律情况对照检查材料
2014/09/26 职场文书
三行辞职书范文
2015/02/26 职场文书
党校团干班培训心得体会
2016/01/06 职场文书
VW、VH适配移动端的解决方案与常见问题
2023/05/21 HTML / CSS