tldr;优先使用
PureComponent
,而且永远不要改变数据对象(或者使用其它最佳实践)github
我使用PureComponent
已经有一段时间,这基于它是一个更具性能的组件版本。redux
事实证实这是真的,可是性能优点带来了一些必要前提。数组
咱们来深刻研究PureComponent
而且理解为何咱们应该去使用它。缓存
Component
个PureComponent
只有一个区别PureComponent
和Component
几乎彻底同样,惟一的区别是PureComponent
为你处理shouldComponentUpdate
事件。安全
当props
或state
发生变化,PureComponent
会对二者都作浅比较
;而Component
则不会对二者的新旧值进行比较。因此,不管什么时候调用shouldComponentUpdate
,组件都会默认触发re-render
。async
译者注:
shouldComponentUpdate
默认返回true
,必定触发re-render
函数
当对props
和state
的新旧值进行比较时,浅比较
只会检查基本数据类型
的值是否相等(好比:1
等于1
或者true
等于true
),复杂如对象
和数组
也是如此,不过是去比较引用值
。工具
你可能听过,不要对props
和state
中的对象
和数组
进行改变。若是你在父组件对对象
进行了改变,你的纯
子组件并不会更新。尽管上游的值发生了改变,可是子组件只会对props
进行引用值
的比较而且没法检测到区别。post
译者注:这里改变,指
不改变
对象引用的操做
而正确的作法是,借助ES6
的object
新特性、array
的扩展运算符
或者使用不可变工具库
来返回新对象
。
译者注:这里改变,指
改变
对象引用的操做
对基本数据类型
的值和引用数据类型
的引用值
比较是个极其廉价的操做。若是你有一组子组件列表而且其中一个更新了,相比于从新渲染全部,在每个子组件上进行props
和state
的比较仍然是一个很是快的过程。
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