Open duyue6002 opened 5 years ago
原文链接:https://codeburst.io/when-to-use-component-or-purecomponent-a60cfad01a81
太长不看版:与Component相比更青睐PureComponent,但绝不要改变你的对象
Component
PureComponent
我选择使用PureComponent有一段时间,因为它是一个更高性能的Component版本,但性能的提升伴随着一些附加条件。 让我们深入了解PureComponent并理解为什么我们应该使用它。
PureComponent实际上和Component完全相同,除了有一点,那就是它会处理shouldComponentUpdate方法。 当props或state发生变化时,PureComponent将对props和state进行浅比较(shallow comparison)。另一方面,Component不会做这个比较操作。 因此,每当调用shouldComponentUpdate时,组件将默认再次render。
shouldComponentUpdate
props
state
render
当比较新旧版本的props和state时,浅比较会检查原始值(primitives)是否具有相同的值(比如,1 === 1 或 true等于true),并且会比较对象或数组之间的引用是否相同。
1 === 1
true等于true
你可能听说过不要在props和state中改变对象和数组,如果你在父组件中改变了对象,你的"pure"子组件将不会更新。尽管上流已经改变了这些值,但子组件将会比较前props的引用,而且检测不到差别。
因此,当你需要做出改变时,使用ES6对象的assign方法或数组的spread扩展符,或使用第三方库,来强制返回新对象。
assign
spread
比较原始值类型和对象引用类型是非常简单的操作。如果你有一列表的子对象并且其中一个子对象更新,做props和state的比较检查远比重新render每个子对象成本小得多。
你可能有一个items列表,每个item传递唯一参数给父方法,为了绑定每个参数,你可能会做如下操作:
这个问题在于每次父组件的render方法被调用,就会创建新方法并将其传入likeComment中。当改变子组件props时会产生一个副作用,就是引起它们当重新渲染,尽管数据本身没有发生变化。
likeComment
为了解决这个问题,只需要将父组件的原型方法的引用传递给子组件。子组件的likeComment属性会永远有相同的引用并且不会产生不必要的重新渲染。
然后在子组件中创建一个引用了传入属性的类方法:
考虑一下profile组件有一系列文章,你需要展示用户最喜欢的10篇。
topTen将在每次组件重新渲染时有全新的引用,尽管posts没有变化,数据也与从前一样。这样就会产生无必要的重新渲染。
topTen
posts
存储派生数据可以解决这个问题,例如,设置这些数据在组件的state中,并且只在posts更新时更新。
如果你使用Redux的话,考虑使用reselect去创建"selectors"以组成并存储派生数据。
Redux
使用PureComponent比Component更安全,需要遵循以下两条规则:1)通常情况下易变是不好的,使用PureComponent会使问题更糟。2)如果你在render方法中创建方法、对象或数组,那么你可能在做一件错事。
原文链接:https://codeburst.io/when-to-use-component-or-purecomponent-a60cfad01a81
什么时候用Component或PureComponent
我选择使用
PureComponent
有一段时间,因为它是一个更高性能的Component
版本,但性能的提升伴随着一些附加条件。 让我们深入了解PureComponent
并理解为什么我们应该使用它。Component和PureComponent有一个不同点
PureComponent
实际上和Component
完全相同,除了有一点,那就是它会处理shouldComponentUpdate
方法。 当props
或state
发生变化时,PureComponent
将对props
和state
进行浅比较(shallow comparison)。另一方面,Component
不会做这个比较操作。 因此,每当调用shouldComponentUpdate
时,组件将默认再次render
。浅比较 101
当比较新旧版本的
props
和state
时,浅比较会检查原始值(primitives)是否具有相同的值(比如,1 === 1
或true等于true
),并且会比较对象或数组之间的引用是否相同。绝不要改变
你可能听说过不要在
props
和state
中改变对象和数组,如果你在父组件中改变了对象,你的"pure"子组件将不会更新。尽管上流已经改变了这些值,但子组件将会比较前props
的引用,而且检测不到差别。因此,当你需要做出改变时,使用ES6对象的
assign
方法或数组的spread
扩展符,或使用第三方库,来强制返回新对象。会有性能问题吗?
比较原始值类型和对象引用类型是非常简单的操作。如果你有一列表的子对象并且其中一个子对象更新,做
props
和state
的比较检查远比重新render
每个子对象成本小得多。其他需要注意的地方
不要在render方法中绑定值
你可能有一个items列表,每个item传递唯一参数给父方法,为了绑定每个参数,你可能会做如下操作:
这个问题在于每次父组件的render方法被调用,就会创建新方法并将其传入
likeComment
中。当改变子组件props
时会产生一个副作用,就是引起它们当重新渲染,尽管数据本身没有发生变化。为了解决这个问题,只需要将父组件的原型方法的引用传递给子组件。子组件的
likeComment
属性会永远有相同的引用并且不会产生不必要的重新渲染。然后在子组件中创建一个引用了传入属性的类方法:
不要在render方法中派生数据
考虑一下profile组件有一系列文章,你需要展示用户最喜欢的10篇。
topTen
将在每次组件重新渲染时有全新的引用,尽管posts
没有变化,数据也与从前一样。这样就会产生无必要的重新渲染。存储派生数据可以解决这个问题,例如,设置这些数据在组件的
state
中,并且只在posts
更新时更新。如果你使用
Redux
的话,考虑使用reselect去创建"selectors"以组成并存储派生数据。总结
使用
PureComponent
比Component
更安全,需要遵循以下两条规则:1)通常情况下易变是不好的,使用PureComponent
会使问题更糟。2)如果你在render方法中创建方法、对象或数组,那么你可能在做一件错事。