在优化 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,}; render() { const { firstName,lastName } = this.context; return ( <div>{firstName} {lastName}</div> ) } }
这个例子其实算是 React 留给我们的一个坑,这里 FullName 是 Pure Component,但是 Segament 却不是,因为 Segament 的 render 结果间接地依赖了上层的 context。