【译】何时使用Component或PureCompoent?

本文对比了React中的PureComponent和Component,阐述了PureComponent如何通过处理shouldComponentUpdate事件提升性能,以及使用时需要注意的问题,例如避免修改props和state中的对象。

原文- When to use Component or PureComponent

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

何时使用Component或PureComponent?

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

事实证明这是真的,但是性能优势带来了一些必要前提。

我们来深入研究PureComponent并且理解为什么我们应该去使用它。

ComponentPureComponent只有一个区别

PureComponentComponent几乎完全一样,唯一的区别是PureComponent为你处理shouldComponentUpdate事件。

propsstate发生变化,PureComponent会对两者都做浅比较;而Component则不会对两者的新旧值进行比较。所以,无论何时调用shouldComponentUpdate,组件都会默认触发re-render

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

浅比较 101

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

不要改变数据

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

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

而正确的做法是,借助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

转载于:https://juejin.im/post/5afc502d6fb9a07ab1115d4a

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值