React性能优化 PureComponent
为什么使用?
React15.3中新加了一个 PureComponent
类,顾名思义, pure
是纯的意思, PureComponent
也就是纯组件,取代其前身 PureRenderMixin
, PureComponent
是优化 React
应用程序最重要的方法之一,易于实施,只要把继承类从 Component
换成 PureComponent
即可,可以减少不必要的 render
操作的次数,从而提高性能,而且可以少写 shouldComponentUpdate
函数,节省了点代码。
原理
当组件更新时,如果组件的 props
和 state
都没发生改变, render
方法就不会触发,省去 Virtual DOM
的生成和比对过程,达到提升性能的目的。具体就是 React
自动帮我们做了一层浅比较:
1
2
3
4
|
if (this._compositeType === CompositeTypes.PureClass) {
shouldUpdate = !shallowEqual(prevProps, nextProps)
|| !shallowEqual(inst.state, nextState);
}
|
而 shallowEqual
又做了什么呢?会比较 Object.keys(state | props)
的长度是否一致,每一个 key
是否两者都有,并且是否是一个引用,也就是只比较了第一层的值,确实很浅,所以深层的嵌套数据是对比不出来的。
使用指南
易变数据不能使用一个引用
案例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
class App extends PureComponent {
state = {
items: [1, 2, 3]
}
handleClick = () => {
const { items } = this.state;
items.pop();
this.setState({ items });
}
render() {
return (<div>
<ul>
{this.state.items.map(i => <li key={i}>{i}</li>)}
</ul>
<button onClick={this.handleClick}>delete</button>
</div>)
}
}
|
会发现,无论怎么点 delete
按钮, li
都不会变少,因为 items
用的是一个引用, shallowEqual
的结果为 true
。改正:
1
2
3
4
5
|
handleClick = () => {
const { items } = this.state;
items.pop();
this.setState({ items: [].concat(items) });
}
|
这样每次改变都会产生一个新的数组,也就可以 render
了。这里有一个矛盾的地方,如果没有 items.pop();
操作,每次 items
数据并没有变,但还是 render
了,这不就很操蛋么?呵呵,数据都不变,你 setState
干嘛?
不变数据使用一个引用
子组件数据
上面易变数据不能使用一个引用的案例中有一个点击删除操作,如果我们删除的代码这么写:
1
2
3
4
5
|
handleClick = () => {
const { items } = this.state;
items.splice(items.length - 1, 1);
this.setState({ items });
}
|
items
的引用也是改变的,但如果 items
里面是引用类型数据:
1
|
items: [{a: 1}, {a: 2}, {a: 3}]
|
这个时候
1
|
state.items[0] === nextState.items[0] // false
|
子组件里还是re-render
了。这样就需要我们保证不变的子组件数据的引用不能改变。这个时候可以使用immutable-js函数库。
函数属性
我们在给组件传一个函数的时候,有时候总喜欢:
1
2
3
4
5
6
7
8
9
|
// 1
<MyInput onChange={e => this.props.update(e.target.value)} />
// 2
update(e) {
this.props.update(e.target.value)
}
render() {
return <MyInput onChange={this.update.bind(this)} />
}
|
由于每次 render
操作 MyInput
组件的 onChange
属性都会返回一个新的函数,由于引用不一样,所以父组件的 render
也会导致 MyInput
组件的 render
,即使没有任何改动,所以需要尽量避免这样的写法,最好这样写:
1
2
3
4
5
6
7
|
// 1,2
update = (e) => {
this.props.update(e.target.value)
}
render() {
return <MyInput onChange={this.update} />
}
|
空对象、空数组或固定对象
有时候后台返回的数据中,数组长度为0或者对象没有属性会直接给一个 null
,这时候我们需要做一些容错:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
class App extends PureComponent {
state = {
items: [{ name: 'test1' }, null, { name: 'test3' }]
}
store = (id, value) => {
const { items } = this.state;
items[id] = assign({}, items[id], { name: value });
this.setState({ items: [].concat(items) });
}
render() {
return (<div>
<ul>
{this.state.items.map((i, k) =>
<Item style={{ color: 'red' }} store={this.store} key={k} id={k} data={i || {}} />)
}
</ul>
</div>)
}
}
|
当某一个子组件调用 store
函数改变了自己的那条属性,触发 render
操作,如果数据是 null
的话 data
属性每次都是一个 {}
,{} ==== {}
是 false
的,这样无端的让这几个子组件重新 render
了。{ color: 'red' }
也是一样。
最好设置一个 defaultValue
为 {}
,如下:
1
2
3
|
static defaultValue = {}
const style = { color: 'red' };
<Item style={style} store={this.store} key={k} id={k} data={i || defaultValue} />
|
复杂状态与简单状态不要共用一个组件
这点可能和 PureComponent
没多少关系,但做的不好可能会浪费很多性能,比如一个页面上面一部分是一个复杂的列表,下面是一个输入框,抽象代码:
1
2
3
4
5
6
7
8
9
10
11
|
change = (e) => {
this.setState({ value: e.target.value });
}
render() {
return (<div>
<ul>
{this.state.items.map((i, k) => <li key={k}> {...}</li>)}
</ul>
<input value={this.state.value} onChange={this.change} />
</div>)
}
|
表单和列表其实是没有什么关联的,表单的值也可能经常变动,但它的会给列表也带来必然的 diff
操作,这是没必要的,最好是给列表抽出成一个单独的 PureComponent
组件,这样 state.items
不变的话,列表就不会重新 render
了。
与 shouldComponentUpdate
共存
如果 PureComponent
里有 shouldComponentUpdate
函数的话,直接使用 shouldComponentUpdate
的结果作为是否更新的依据,没有 shouldComponentUpdate
函数的话,才会去判断是不是 PureComponent
,是的话再去做 shallowEqual
浅比较。
1
2
3
4
5
6
7
8
9
10
11
|
// 这个变量用来控制组件是否需要更新
var shouldUpdate = true;
// inst 是组件实例
if (inst.shouldComponentUpdate) {
shouldUpdate = inst.shouldComponentUpdate(nextProps, nextState, nextContext);
} else {
if (this._compositeType === CompositeType.PureClass) {
shouldUpdate = !shallowEqual(prevProps, nextProps) ||
!shallowEqual(inst.state, nextState);
}
}
|
老版本兼容写法
1
2
3
4
5
|
import React { PureComponent, Component } from 'react';
class Foo extends (PureComponent || Component) {
//...
}
|
这样在老版本的 React
里也不会挂掉。
总结
PureComponent
真正起作用的,只是在一些纯展示组件上,复杂组件用了也没关系,反正 shallowEqual
那一关就过不了,不过记得 props
和 state
不能使用同一个引用哦。
React性能优化 PureComponent的更多相关文章
- React性能优化之PureComponent 和 memo使用分析
前言 关于react性能优化,在react 16这个版本,官方推出fiber,在框架层面优化了react性能上面的问题.由于这个太过于庞大,我们今天围绕子自组件更新策略,从两个及其微小的方面来谈rea ...
- react性能优化
前面的话 本文将详细介绍react性能优化 避免重复渲染 当一个组件的props或者state改变时,React通过比较新返回的元素和之前渲染的元素来决定是否有必要更新实际的DOM.当他们不相等时,R ...
- React性能优化记录(不定期更新)
React性能优化记录(不定期更新) 1. 使用PureComponent代替Component 在新建组件的时候需要继承Component会用到以下代码 import React,{Componen ...
- 关于React性能优化
这几天陆陆续续看了一些关于React性能优化的博客,大部分提到的都是React 15.3新加入的PureComponent ,通过使用这个类来减少React的重复渲染,从而提升页面的性能.使用过Rea ...
- React 性能优化 All In One
React 性能优化 All In One Use CSS Variables instead of React Context https://epicreact.dev/css-variables ...
- react组件性能优化PureComponent
首先我们使用react组件会配合connect来连接store获取state,那么只要store中的state发生改变组件就会重新渲染,所以性能不高,一般我们可以使用shouldComponentUp ...
- React性能优化总结(转)
原文链接: https://segmentfault.com/a/1190000007811296?utm_source=tuicool&utm_medium=referral 初学者对Rea ...
- react性能优化要点
1.减少render方法的调用 1.1继承React.PureComponent(会自动在内部使用shouldComponentUpdate方法对state或props进行浅比较.)或在继承自Reac ...
- React性能优化总结
本文主要对在React应用中可以采用的一些性能优化方式做一下总结整理 前言 目的 目前在工作中,大量的项目都是使用react来进行开展的,了解掌握下react的性能优化对项目的体验和可维护性都有很大的 ...
随机推荐
- [原][译][osgearth]样式表style中参数总结(OE官方文档翻译)
几何Geometry 高度Altitude 挤压Extrusion 图标Icon 模型Model 渲染Render 皮肤Skin 文本Text 覆盖Coverage 提示: 在SDK中,样式表的命名空 ...
- PHP自定义XML类实现数组到XML文件的转换
这两天在公司写和各应用商店应用内搜索的接口,大致就像百度应用内搜索这样的东西,具体可以点下面的链接查看. 百度应用内搜索 有的应用商店需要JSON格式的数据,所以我只需要用下面的语句就可以返回对方服务 ...
- 一.UTF8字符集csv文件在oracle下乱码问题处理
1.问题描述 在excel中生成了一个UTF-8编码格式的csv文件准备导入数据库,在notpad++下打开显示正常,编码集为UTF-8,通过pl/sql dev导入oracle是出现乱码,此时初步推 ...
- Eclipse 常用快捷键和使用技巧
1.查看快捷键定义的地方 Window->Preferences->General->Keys. 2.更改启动页 在AndroidManifest.xml第一个activity标签项 ...
- Xcode8出现问题总结
上点干货,目前得知的一些bug解决汇总:iOS10相册相机闪退bughttp://www.jianshu.com/p/5085430b029fiOS 10 因苹果健康导致闪退 crashhttp:// ...
- BZOJ3296:Learning Languages(简单并查集)
3296: [USACO2011 Open] Learning Languages Time Limit: 5 Sec Memory Limit: 128 MBSubmit: 436 Solved ...
- 用 dotTrace 进行性能分析时,各种不同性能分析选项的含义和用途
对 .NET 程序进行性能分析,dotTrace 能应对绝大多数的场景.在开启一个进程进行性能分析之前,我们会看到一些性能分析选项(Profiler Options).本文将介绍这几个选项的含义,并用 ...
- Oracle序列和伪表
创建序列 create sequence sq_teacher_tnostart with 10 从哪一个数字开始increment by 1 每次增长的数字maxvalue 999999999999 ...
- Python面试题(十六)
1.取出两个升序数组中的最小的一半的元素组成一个新的升序数组. map(lambda x, y: x if x < y else y, a, b) 答案 2.用至少2种不同的方式删除一个list ...
- cratedb json 数据导入
基本环境的搭建,可以参考相关文档,或者直接使用docker 安装 docker run -d -p 4200:4200 crate 导出mongodb数据(可选,同时使用工具进行数据类型转换) mon ...