在优化 React 组件的时候我们常常会看到 Pure Component 的说法,所谓 Pure Component 就是在 props,state 和 context 不变的情况下,组件的 render 结果也是不变的。基于这个前提,我们可以很方便地用 shouldCompoentUpdate 来优化组件,减少 render。
import React, { Component } from 'react';
import shallowequal from 'shallowequal';
class FullName extends Component {
shouldComponentUpdate(nextProps) {
return !shallowequal(this.props, nextProps)
}
render() {
const { firstName, lastName } = this.props;
return (
<div>{firstName} {lastName}</div>
)
}
}
React 官方也提供了 PureRenderMixin (给 React.createClass 用)和 React.PureComponent 来让我们方便地声明一个 Pure Component。
那么既然有 Pure Component 的说法,肯定还有相对的 Impure Component。一言以蔽之,只要你的组件依赖了 props 和 state (context 比较特殊,后面会讲到)之外的数据,你的组件就不是 pure 的,我们来看例子。
例子一
class FullName extends Component {
render() {
const { firstName, lastName } = this.props;
return (
<div>{firstName} {lastName} - {new Date}</div>
)
}
}
我们在这里增加了一个当前日期的显示,导致即使 firstName 和 lastName 不变化,组件每次 render 的结果也是不同的,这个组件就没办法用 shouldCompoentUpdate 去优化了。
例子二
class App extends Component {
state = {
lastName: '',
}
handleChange = e => {
this.setState({ lastName: e.target.value });
}
renderLastName = () => {
return this.state.lastName;
}
render() {
<div>
<input type="text" onChange={this.handleChange} />
<FullName firstName="Ava" lastName={this.renderLastName} />
</div>
}
}
class FullName extends Component {
render() {
const { firstName, lastName } = this.props;
return (
<div>{firstName} {lastName()}</div>
)
}
}
这个例子我们把 lastName 变成一个方法传进来,这样其实 FullName 组件通过闭包,而不是通过 props,依赖了 App 的 state.lastName ,导致在 firstName 和 lastName 都不变化的情况下,FullName 会根据 state.lastName 的不同 render 出不同的结果。
例子三
class App extends Component {
static childContextTypes = {
firstName: React.PropTypes.string,
lastName: React.PropTypes.string,
}
getChildContext() {
return {
firstName: 'Taylor',
lastName: 'Swift',
};
}
render() {
<Segment>
<FullName />
</Segment>
}
}
class Segment extends Component {
render() {
<div>{this.props.children}</div>
}
}
class FullName extends Component {
static contextTypes = {
firstName: React.PropTypes.string,
lastName: React.PropTypes.string,
};
render() {
const { firstName, lastName } = this.context;
return (
<div>{firstName} {lastName}</div>
)
}
}
这个例子其实算是 React 留给我们的一个坑,这里 FullName 是 Pure Component,但是 Segament 却不是,因为 Segament 的 render 结果间接地依赖了上层的 context。