从得知的 react v15.3.0 ,我们有一个名为 的新基类PureComponent 扩展 PureRenderMixin 内置。我的理解是,在引擎盖下,这使用了对 shouldComponentUpdate 内部 Prop 的浅层比较。 .
现在我们有 3 种方法来定义 React 组件:
PureComponent 的组件类(class)Component 的普通组件类(class)一段时间以前,我们曾经将无状态组件称为纯组件,甚至是哑组件。似乎“纯”这个词的整个定义现在在 React 中已经改变了。
虽然我了解这三个之间的基本区别,但我仍然不确定 何时选择什么 .此外,每种方法的性能影响和权衡是什么?
更新 :
这些是我希望得到澄清的问题:
PureComponent类(为了性能)? 我失去了简单?
Component上课时我总是可以使用 PureComponent为了更好的性能? 请您参考如下方法:
您如何决定,如何根据我们组件的用途/大小/ Prop /行为在这三个之间进行选择?
延伸自 React.PureComponent或来自 React.Component带定制 shouldComponentUpdate方法具有性能影响。使用无状态功能组件是一种“架构”选择,并且没有任何开箱即用的性能优势(目前)。
shouldComponentUpdate)。 PureComponent如果您知道您的输出取决于简单的 Prop /状态(“简单”意味着没有嵌套的数据结构,因为 PureComponent 执行浅比较)并且您需要/可以获得一些性能改进。 Component并实现您自己的 shouldComponentUpdate如果您需要通过在 next/current props 和 state 之间执行自定义比较逻辑来提高性能。例如,您可以使用 lodash#isEqual 快速执行深度比较:class MyComponent extends Component {
shouldComponentUpdate (nextProps, nextState) {
return !_.isEqual(this.props, nextProps) || !_.isEqual(this.state, nextState);
}
}
此外,实现您自己的
shouldComponentUpdate或从
PureComponent 延伸是优化,和往常一样,只有在遇到性能问题(
avoid premature optimizations )时才应该开始研究。
根据经验,我总是在应用程序处于工作状态后尝试进行这些优化,其中大部分功能已经实现。当性能问题真正成为障碍时,将注意力集中在性能问题上要容易得多。
更多细节
功能性无状态组件:
这些只是使用函数定义的。由于无状态组件没有内部状态,因此输出(呈现的内容)仅取决于作为此函数输入的 Prop 。
优点:
缺点:
componentDidMount和其他 friend 。通常,您在层次结构中较高的父组件中执行此操作,以便您可以将所有子组件转换为无状态组件。 shouldComponentUpdate .每次组件收到新的 props 时都会重新渲染(无法进行浅层比较等)。 future ,React 可以自动优化无状态组件,目前有一些库可以使用。由于无状态组件只是函数,基本上就是“函数内存”的经典问题。 扩展 PureComponent 类的组件 VS 扩展 Component 类的普通组件:
React 曾经有一个
PureRenderMixin您可以附加到使用
React.createClass 定义的类句法。 mixin 将简单地定义一个
shouldComponentUpdate在下一个 Prop 和下一个状态之间进行浅层比较以检查是否有任何更改。如果没有任何变化,则无需执行重新渲染。
如果要使用 ES6 语法,则不能使用 mixins。所以为了方便,React 引入了
PureComponent您可以继承的类而不是使用
Component .
PureComponent只是实现
shouldComponentUpdate以同样的方式
PureRendererMixin .这主要是一件方便的事情,因此您不必自己实现它,因为当前/下一个状态和 Prop 之间的浅薄比较可能是最常见的场景,可以让您快速获得性能优势。
例子:
class UserAvatar extends Component {
render() {
return <div><img src={this.props.imageUrl} /> {{ this.props.username }} </div>
}
}
如您所见,输出取决于
props.imageUrl和
props.username .如果在父组件中渲染
<UserAvatar username="fabio" imageUrl="http://foo.com/fabio.jpg" />使用相同的 props,React 会调用
render每次,即使输出完全相同。请记住,尽管 React 实现了 dom diffing,因此实际上不会更新 DOM。尽管如此,执行 dom diffing 可能很昂贵,所以在这种情况下,这将是一种浪费。
如果
UserAvatar组件扩展
PureComponent相反,执行浅比较。并且因为 props 和 nextProps 是一样的,
render根本不会被调用。
React 中“纯”的定义注意事项:
通常,“纯函数”是在给定相同输入的情况下始终评估为相同结果的函数。输出(对于 React,这是
render 方法返回的内容)不依赖于任何历史/状态,也没有任何副作用(改变函数外部“世界”的操作)。
在 React 中,如果您将“无状态”称为从不调用
this.setState 的组件,则无状态组件不一定是上述定义的纯组件。这不使用
this.state .
事实上,在
PureComponent ,您仍然可以在生命周期方法期间执行副作用。例如,您可以在
componentDidMount 中发送一个 ajax 请求。或者您可以执行一些 DOM 计算来动态调整
render 内 div 的高度.
“哑组件”定义有一个更“实用”的含义(至少在我的理解中):哑组件通过 props “被告知”父组件要做什么,并且不知道如何做事但使用 props而是回调。
“智能”示例
AvatarComponent :
class AvatarComponent extends Component {
expandAvatar () {
this.setState({ loading: true });
sendAjaxRequest(...).then(() => {
this.setState({ loading: false });
});
}
render () {
<div onClick={this.expandAvatar}>
<img src={this.props.username} />
</div>
}
}
“哑巴”示例
AvatarComponent :
class AvatarComponent extends Component {
render () {
<div onClick={this.props.onExpandAvatar}>
{this.props.loading && <div className="spinner" />}
<img src={this.props.username} />
</div>
}
}
最后,我会说“愚蠢”、“无状态”和“纯”是完全不同的概念,有时可能会重叠,但不一定,主要取决于您的用例。






