在React.js中使用PureComponent的重要性和使用方式

GladisYQUT 8年前
   <h3>一、介绍PureComponent</h3>    <p>React 15.3在2016.06.29发布了,这个版本最值得关注的是支持了 <strong>React.PureComponent</strong> ,它取代了之前的 <strong>pure-render-mixin</strong> 。在本文中,我们将讨论 <strong>PureComponent</strong> 的重要性和使用场景。</p>    <p>React.PureComponent最重要的一个用处就是优化React应用,这很容易快速地实现。使用 <strong>React.PureComponent</strong> 对性能的提升是非常可观的,因为它减少了应用中的渲染次数。</p>    <p><img src="https://simg.open-open.com/show/e17b6ee13c3b3b3acc00dbc35603255c.gif"></p>    <p>PureComponent改变了生命周期方法 shouldComponentUpdate ,并且它会自动检查组件是否需要重新渲染。这时,只有PureComponent检测到 state 或者 props 发生变化时,PureComponent才会调用 render 方法,因此,你不用手动写额外的检查,就可以在很多组件中改变 state , 例如:</p>    <pre>  <code class="language-javascript">if (this.state.someVal !== computedVal) {    this.setState({ someVal: computedVal })  }</code></pre>    <p>根据React源码,如果组件是纯组件(Pure Component),那么一下比较是很容易理解的:</p>    <pre>  <code class="language-javascript">if (this._compositeType === CompositeTypes.PureClass) {    shouldUpdate = !shallowEqual(prevProps, nextProps) || ! shallowEqual(inst.state, nextState);  }</code></pre>    <p>其中, shadowEqual 只会"浅"检查组件的 props 和 state ,这就意味着嵌套对象和数组是不会被比较的。</p>    <p>深比较操作是非常昂贵的,同时,如果这个组件还是纯组件(PureComponent),那么深比较将会更浪费。另外,你也可以使用 shouldComponentUpdate 来手动确定组件是否需要重新渲染。最简单的方式就是直接比较 props 或 state :</p>    <pre>  <code class="language-javascript">shouldComponentUpdate(nextProps, nextState) {    return nextProps.user.id === props.user.id;  }</code></pre>    <p>除此之外,你可以使用 immutable 属性。这种情况下,属性的比较是非常容易的,因为已存在的对象不会发生改变,取而代之的是重新创建新的对象。其中, <a href="/misc/goto?guid=4959660193525766484" rel="nofollow,noindex">Immutable.js</a> 就是非常好的Immutable库。</p>    <h3>二、使用PureComponent</h3>    <p>PureComponent节约了我们的时间,避免了多余的代码。那么,掌握如何正确使用它是非常重要的,否则如果使用不当,它就无法发挥作用。因为PureComponent仅仅是浅比较(shadow comparison),所以改变组件内部的 props 或者 state ,它将不会发挥作用。例如,让我们想想这样一种情况,父组件有一个render方法和一个click处理方法:</p>    <pre>  <code class="language-javascript">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>    )  }</code></pre>    <p>如果ItemList是纯组件(PureComponent),那么这时它是不会被渲染的,因为尽管 this.state.items 的值发生了改变,但是它仍然指向同一个对象的引用。但是,通过移除可变对象就很容易改变这种情况,使之能够正确被渲染。</p>    <pre>  <code class="language-javascript">handleClick() {    this.setState(prevState => ({      words: prevState.items.concat(['new-item'])    }));  }</code></pre>    <p>如果一个纯组件(PureComponent)的 state 或 props 引用了一个新对象,那么这个组件就会被重新渲染(re-render)。这暗示着,如果不想损失PureComponent的优点,那么我们应该避免以下的结构:</p>    <pre>  <code class="language-javascript"><Entity values={this.props.values || []}/></code></pre>    <p>如上面代码,新数组,即便是空数组,总是会迫使组件重新渲染。为了避免这个问题,你可以使用 defaultProps ,它包含了一个属性的初始化空状态。解决这个问题的另一种方法如下:</p>    <pre>  <code class="language-javascript"><CustomInput onChange={e => this.props.update(e.target.value)} /></code></pre>    <p>在纯组件(PureComponent)被创建时,因为函数的新对象被创建了,所以它会获得新数据,并且重新渲染。解决这个问题最简单的方法就是: 在组件的 constructor 方法中使用 bind 。</p>    <pre>  <code class="language-javascript">constructor(props) {      super(props)      this.update = this.update.bind(this)  }  update(e) {      this.props.update(e.target.value)  }  render() {      return <MyInput onChange={this.update} />  }</code></pre>    <p>同时,在JSX中,任何包含子元素(child elements)的组件, shallowEqual 检查总会返回false。</p>    <p>请谨记:纯组件忽略重新渲染时,不仅会影响它本身,而且会影响它的说有子元素,所以,使用PureComponent的最佳情况就是展示组件,它既没有子组件,也没有依赖应用的全局状态。</p>    <h3>三、总结</h3>    <p>事实上,如果你已经意识到 shallowEqual 和 JS References 的特性,过渡到PureComponent是相当容易的。正常情况下,迁移的方式非常简单,就像改变组件继承的基类,从</p>    <pre>  <code class="language-javascript">class MyComponent extends Component {...}</code></pre>    <p>到</p>    <pre>  <code class="language-javascript">class MyComponent extends PureComponent {...}</code></pre>    <p>这样不仅能平滑过渡,甚至可以提升性能。所以,我极力推荐所有人在开发应用中使用PureComponent。</p>    <h3>四、注意</h3>    <p>在纯组件有子组件的时候,所有基于 this.context 改变的子组件, <a href="/misc/goto?guid=4959734770123715015" rel="nofollow,noindex"> 在 this.context 改变时, 将不会重新渲染 </a> ,除非在父组件(Parent ParentComponent)中声明 contextTypes 。</p>    <p>本文翻译至 <a href="/misc/goto?guid=4959734770213400451" rel="nofollow,noindex">habrahabr</a> 。</p>    <p> </p>    <p>来自:http://www.zcfy.cc/article/why-and-how-to-use-purecomponent-in-react-js-60devs-2344.html</p>    <p> </p>