React 性能优化(高级)
性能优化对于 React 更加重要
- shouldComponentUpdate(简称 SCU)
- PureComponent 和 React.memo
- 不可变值 immutable.js
shouldComponentUpdate
SCU 基本用法
js
shouldComponentUpdate(nextProps, nextState, nextContext) {
if (nextState.count !== this.state.count) {
return true // 可以渲染
}
return false // 不重复渲染
}
SCU 默认返回 true
父组件有更新,子组件则无条件也更新
js
// 子组件
class Footer extends React.Component {
constructor(props) {
super(props);
}
render() {
return <p>{this.props.text}</p>;
}
componentDidUpdate() {
// 当更新父组件时,会一直执行此
console.log('footer add update');
}
// shouldComponentUpdate 默认返回 true
shouldComponentUpdate(nextProps, nextState, nextContext) {
if (nextProps.text !== this.props.text) {
return true; // 可以渲染
}
return false; // 不重复渲染
}
// React 默认:父组件有更新,子组件则无条件也更新
// 性能优化对于 React 更加重要
}
// 父组件
class TodoListDemo extends React.Component {
constructor(props) {
super(props);
this.state = {
footerInfo: '底部文字',
};
}
render() {
return (
<div>
<Footer text={this.state.footerInfo} />
</div>
);
}
}
SCU 每次都要吗?
- 需要时才优化,比如上面的例子
- 一定要配合不可变值,比如下面的例子
例子
js
// 子组件
class List extends React.Component {
constructor(props) {
super(props);
}
render() {
// 子组件接收参数
const { list } = this.props;
return (
<ul>
{list.map((item, index) => {
return (
<li key={item.id}>
<span>{item.title}</span>
</li>
);
})}
</ul>
);
}
// 增加 shouldComponentUpdate
shouldComponentUpdate(nextProps, nextState, nextContext) {
// lodash.isEqual 做对象或者数组的深度比较
if (lodash.isEqual(nextProps.list, this.props.list)) {
// 相等,则不重复渲染
return false;
}
return true; // 不相等,则渲染
}
}
SCU 使用总结
- SCU 默认返回 true,即 React 默认重新渲染所有子组件
- 必须配合“不可变值”一起使用
- 可先不用 SCU,有性能问题时再考虑使用
PureComponent 和 memo
- PureComponent,SCU 中实现了浅比较
- memo,函数组件中的 PureComponent
- 浅比较已适用大部分情况(尽量不要做深度比较)
PureComponent 例子
js
class PureComponentDemo extends React.PureComponent {
constructor(props) {
super(props);
}
shouldComponentUpdate() {
// 浅比较
}
}
memo 例子
js
function MyComponent(props) {
// 使用 props 渲染
}
function areEqual(prevProps, nextProps) {
// 如果把 nextProps 传入 render 方法的返回结果
// 与将 prevProps 传入 render 方法的返回结果一致的话则返回 true,
// 否则返回 false
}
export default React.memo(MyComponent, areEqual);
使用 immutable.js
- 彻底拥抱“不可变值”
- 基于共享数据(不是深拷贝),速度好
- 有一定学习和迁移成本,按需使用
例子
js
const map1 = Immutable.Map({ a: 1, b: 2, c: 3 });
const map2 = map1.set('b', 50);
console.log(map1.get('b')); // 2
console.log(map2.get('b')); // 50