duyue6002 / Blog

:pencil2: Write here
http://duyue6002.github.io/Blog/#/
5 stars 1 forks source link

[译]什么时候用Component或PureComponent #24

Open duyue6002 opened 5 years ago

duyue6002 commented 5 years ago

原文链接:https://codeburst.io/when-to-use-component-or-purecomponent-a60cfad01a81

太长不看版:与Component相比更青睐PureComponent,但绝不要改变你的对象

什么时候用Component或PureComponent

我选择使用PureComponent有一段时间,因为它是一个更高性能的Component版本,但性能的提升伴随着一些附加条件。 让我们深入了解PureComponent并理解为什么我们应该使用它。

Component和PureComponent有一个不同点

PureComponent实际上和Component完全相同,除了有一点,那就是它会处理shouldComponentUpdate方法。propsstate发生变化时,PureComponent将对propsstate进行浅比较(shallow comparison)。另一方面,Component不会做这个比较操作。 因此,每当调用shouldComponentUpdate时,组件将默认再次render

浅比较 101

当比较新旧版本的propsstate时,浅比较会检查原始值(primitives)是否具有相同的值(比如,1 === 1true等于true),并且会比较对象或数组之间的引用是否相同。

绝不要改变

你可能听说过不要在propsstate中改变对象和数组,如果你在父组件中改变了对象,你的"pure"子组件将不会更新。尽管上流已经改变了这些值,但子组件将会比较前props的引用,而且检测不到差别。

因此,当你需要做出改变时,使用ES6对象的assign方法或数组的spread扩展符,或使用第三方库,来强制返回新对象。

会有性能问题吗?

比较原始值类型和对象引用类型是非常简单的操作。如果你有一列表的子对象并且其中一个子对象更新,做propsstate的比较检查远比重新render每个子对象成本小得多。

其他需要注意的地方

不要在render方法中绑定值

你可能有一个items列表,每个item传递唯一参数给父方法,为了绑定每个参数,你可能会做如下操作:

item bind

这个问题在于每次父组件的render方法被调用,就会创建新方法并将其传入likeComment中。当改变子组件props时会产生一个副作用,就是引起它们当重新渲染,尽管数据本身没有发生变化。

为了解决这个问题,只需要将父组件的原型方法的引用传递给子组件。子组件的likeComment属性会永远有相同的引用并且不会产生不必要的重新渲染。

change  bind

然后在子组件中创建一个引用了传入属性的类方法:

不要在render方法中派生数据

考虑一下profile组件有一系列文章,你需要展示用户最喜欢的10篇。

topTen将在每次组件重新渲染时有全新的引用,尽管posts没有变化,数据也与从前一样。这样就会产生无必要的重新渲染。

存储派生数据可以解决这个问题,例如,设置这些数据在组件的state中,并且只在posts更新时更新。

如果你使用Redux的话,考虑使用reselect去创建"selectors"以组成并存储派生数据。

总结

使用PureComponentComponent更安全,需要遵循以下两条规则:1)通常情况下易变是不好的,使用PureComponent会使问题更糟。2)如果你在render方法中创建方法、对象或数组,那么你可能在做一件错事。