得知的 react v15.3.0 ,我们有一个名为 的新基类PureComponent 扩展 PureRenderMixin 内置。我的理解是,在引擎盖下,这使用了对 shouldComponentUpdate 内部 Prop 的浅层比较。 .
现在我们有 3 种方法来定义 React 组件:

  • 不扩展任何类的功能性无状态组件
  • 扩展 PureComponent 的组件类(class)
  • 扩展 Component 的普通组件类(class)

  • 一段时间以前,我们曾经将无状态组件称为纯组件,甚至是哑组件。似乎“纯”这个词的整个定义现在在 React 中已经改变了。
    虽然我了解这三个之间的基本区别,但我仍然不确定 何时选择什么 .此外,每种方法的性能影响和权衡是什么?

    更新 :
    这些是我希望得到澄清的问题:
  • 我应该选择将我的简单组件定义为函数式(为了简单起见)还是扩展 PureComponent类(为了性能)?
  • 性能提升是否是我真正的权衡
    我失去了简单?
  • 我是否需要扩展正常的 Component上课时我总是可以使用 PureComponent为了更好的性能?
  • 请您参考如下方法:

    您如何决定,如何根据我们组件的用途/大小/ Prop /行为在这三个之间进行选择?

    延伸自 React.PureComponent或来自 React.Component带定制 shouldComponentUpdate方法具有性能影响。使用无状态功能组件是一种“架构”选择,并且没有任何开箱即用的性能优势(目前)。

  • 对于需要轻松重用的简单的、仅展示性的组件,更喜欢无状态的功能组件。通过这种方式,您可以确保它们与实际的应用程序逻辑分离,它们非常容易测试并且它们没有意外的副作用。异常(exception)情况是,如果出于某种原因您有很多它们,或者您确实需要优化它们的渲染方法(因为您无法为无状态功能组件定义 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 。

    优点:
  • 在 React 中定义组件的最简单方法。如果您不需要管理任何状态,为什么还要为类和继承而烦恼呢?函数和类之间的主要区别之一是,对于该函数,您可以确定输出仅取决于输入(而不取决于之前执行的任何历史记录)。
  • 理想情况下,在您的应用程序中,您的目标应该是拥有尽可能多的无状态组件,因为这通常意味着您将逻辑移到 View 层之外并将其移至诸如 redux 之类的东西,这意味着您可以测试您的真实逻辑而无需渲染任何内容(更容易测试,更可重用等)。

  • 缺点:
  • 没有生命周期方法。你没有办法定义 componentDidMount和其他 friend 。通常,您在层次结构中较高的父组件中执行此操作,以便您可以将所有子组件转换为无状态组件。
  • 无法手动控制何时需要重新渲染,因为您无法定义 shouldComponentUpdate .每次组件收到新的 props 时都会重新渲染(无法进行浅层比较等)。 future ,React 可以自动优化无状态组件,目前有一些库可以使用。由于无状态组件只是函数,基本上就是“函数内存”的经典问题。
  • 不支持引用:https://github.com/facebook/react/issues/4936

  • 扩展 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.imageUrlprops.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> 
        } 
    } 
    

    最后,我会说“愚蠢”、“无状态”和“纯”是完全不同的概念,有时可能会重叠,但不一定,主要取决于您的用例。


    评论关闭
    IT虾米网

    微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!