详解在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 validate 中文API 附validate.js中文api手册
Jul 31 Javascript
jQuery页面滚动浮动层智能定位实例代码
Aug 23 Javascript
jquery全选/全不选/反选另一种实现方法(配合原生js)
Apr 07 Javascript
js菜单点击显示或隐藏效果的简单实例
Jan 13 Javascript
使用bootstrap validator的remote验证代码经验分享(推荐)
Sep 21 Javascript
基于JavaScript实现飘落星星特效
Aug 10 Javascript
js合并两个数组生成合并后的key:value数组
May 09 Javascript
Vue项目查看当前使用的elementUI版本的方法
Sep 27 Javascript
jQuery zTree插件快速实现目录树
Aug 16 jQuery
基于JS抓取某高校附近共享单车位置 使用web方式展示位置变化代码实例
Aug 27 Javascript
在layer弹层layer.prompt中,修改placeholder的实现方法
Sep 27 Javascript
Vue使用Ref跨层级获取组件的步骤
Jan 25 Vue.js
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
apache2.2.4+mysql5.0.77+php5.2.8安装精简
2009/04/29 PHP
常用的PHP数据库操作方法(MYSQL版)
2011/06/08 PHP
深入apache host的配置详解
2013/06/09 PHP
PHP模块memcached使用指南
2014/12/08 PHP
php计划任务之验证是否有多个进程调用同一个job的方法
2015/12/07 PHP
Laravel框架实现多数据库连接操作详解
2019/07/12 PHP
php和html的区别点详细总结
2019/09/24 PHP
laravel框架select2多选插件初始化默认选中项操作示例
2020/02/18 PHP
PHP哈希表实现算法原理解析
2020/12/11 PHP
定义select的边框颜色
2008/04/28 Javascript
比较全的JS checkbox全选、取消全选、删除功能代码
2008/12/19 Javascript
使用javascript获取flash加载的百分比的实现代码
2011/05/25 Javascript
jQuery源码分析-03构造jQuery对象-源码结构和核心函数
2011/11/14 Javascript
jquery中dom操作和事件的实例学习-表单验证
2011/11/30 Javascript
JS常用字符串处理方法应用总结
2014/05/22 Javascript
获取阴历(农历)和当前日期的js代码
2016/02/15 Javascript
javascript和jQuery实现网页实时聊天的ajax长轮询
2016/07/20 Javascript
Vue中使用vux的配置详解
2017/05/05 Javascript
js实现图片轮播效果学习笔记
2017/07/26 Javascript
微信小程序显示下拉列表功能【附源码下载】
2017/12/12 Javascript
vue this.reload 方法 配置
2018/09/12 Javascript
jQuery 筛选器简单操作示例
2019/10/02 jQuery
Python heapq使用详解及实例代码
2017/01/25 Python
python实现画圆功能
2018/01/25 Python
Tensorflow之Saver的用法详解
2018/04/23 Python
Python 实现中值滤波、均值滤波的方法
2019/01/09 Python
python列表每个元素同增同减和列表元素去空格的实例
2019/07/20 Python
Python datetime模块的使用示例
2021/02/02 Python
String和StringBuffer的区别
2015/08/13 面试题
C#笔试题和英文面试题
2013/02/07 面试题
营销主管自我评价怎么写
2013/09/19 职场文书
2014年个人思想工作总结
2014/11/27 职场文书
给老婆的检讨书1000字
2015/01/01 职场文书
2015年秋季小学开学典礼主持词
2015/07/16 职场文书
pytorch 实现在测试的时候启用dropout
2021/05/27 Python
sentinel支持的redis高可用集群配置详解
2022/04/01 Redis