【译】什么时候使用Component或PureCompoent?

原文- When to use Component or PureComponentgit

tldr;优先使用PureComponent,而且永远不要改变数据对象(或者使用其它最佳实践)github

什么时候使用Component或PureComponent?

我使用PureComponent已经有一段时间,这基于它是一个更具性能的组件版本。redux

事实证实这是真的,可是性能优点带来了一些必要前提。数组

咱们来深刻研究PureComponent而且理解为何咱们应该去使用它。缓存

ComponentPureComponent只有一个区别

PureComponentComponent几乎彻底同样,惟一的区别是PureComponent为你处理shouldComponentUpdate事件。安全

propsstate发生变化,PureComponent会对二者都作浅比较;而Component则不会对二者的新旧值进行比较。因此,不管什么时候调用shouldComponentUpdate,组件都会默认触发re-renderasync

译者注:shouldComponentUpdate默认返回true,必定触发re-render函数

浅比较 101

当对propsstate的新旧值进行比较时,浅比较只会检查基本数据类型的值是否相等(好比:1等于1或者true等于true),复杂如对象数组也是如此,不过是去比较引用值工具

不要改变数据

你可能听过,不要对propsstate中的对象数组进行改变。若是你在父组件对对象进行了改变,你的子组件并不会更新。尽管上游的值发生了改变,可是子组件只会对props进行引用值的比较而且没法检测到区别。post

译者注:这里改变,指不改变对象引用的操做

而正确的作法是,借助ES6object新特性、array扩展运算符或者使用不可变工具库来返回新对象

译者注:这里改变,指改变对象引用的操做

以上操做会形成性能问题吗?

基本数据类型的值和引用数据类型引用值比较是个极其廉价的操做。若是你有一组子组件列表而且其中一个更新了,相比于从新渲染全部,在每个子组件上进行propsstate的比较仍然是一个很是快的过程。

其余一些注意点

不要在render中的函数绑定值

好比你父组件里面有一组子组件列表,每个都传给父组件方法一个惟一的参数。为了绑定这个参数,你可能这样作:

<CommentItem likeComment={() => this.likeComment(user.id)} />
复制代码

问题是每一次父组件的render方法调用时,一个新函数(伴随着新的引用)就会被建立而且传递给likeComment属性。这会致使一些反作用:每个子组件的props都发生改变,最终致使他们所有从新渲染,哪怕数据自己并无发生变化。

解决这个问题的方法是,仅仅传入父组件原型链方法的引用给子组件。子组件的likeComment属性永远都有相同的引用值而且永远不会引发没必要要的re-render

<CommentItem likeComment={this.likeComment} userID={user.id} />
复制代码

那么子组件仅须要建立一个类方法而且引用它的props便可:

class CommentItem extends PureComponent {
  ...
  handleLike() {
    this.props.likeComment(this.props.userID)
  }
  ...
}
复制代码

不要在render方法中获取数据

考虑你的profile组件须要显示用户的10个最受欢迎的文章:

render() {
  const { posts } = this.props
  const topTen = posts.sort((a, b) => b.likes - a.likes).slice(0, 9)
  return //...
}
复制代码

组件每次re-render时,topTen变量都会是一个全新的引用值,哪怕posts变量值没有发生改变或者slice的结果也没有发生变化。但这仍然会对文章列表产生没有必要的re-render

你能够缓存你获取的数据来解决这个问题。好比,把获取数据操做放入state中,而且仅在posts属性发生更新时更新。

componentWillMount() {
  this.setTopTenPosts(this.props.posts)
}
componentWillReceiveProps(nextProps) {
  if (this.props.posts !== nextProps.posts) {
    this.setTopTenPosts(nextProps)
  }
}
setTopTenPosts(posts) {
  this.setState({
    topTen: posts.sort((a, b) => b.likes - a.likes).slice(0, 9)
  })
}
复制代码

若是你使用Redux,考虑使用reselect来建立选择器去组合而且缓存你获取的数据。

最后

只要你明确如下两点,相比于Component,使用PureComponent就很安全:

  • 改变数据一般是很差的,尤为是使用PureComponent时会让问题更复杂

  • 若是你在render方法中建立了新函数对象数组,那么你的作法是错的

感谢Daniel Min将这篇文章翻译至Korean

相关文章
相关标签/搜索