反应功能无状态组件,PureComponent,Component;有什么区别,何时应该使用什么? [英] React functional stateless component, PureComponent, Component; what are the differences and when should we use what?

查看:911
本文介绍了反应功能无状态组件,PureComponent,Component;有什么区别,何时应该使用什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

来自 React v15.3.0

,我们有一个名为 PureComponent 的新基类,可以使用内置的 PureRenderMixin 扩展。我所了解的是,在引擎盖下,这使用 shouldComponentUpdate 中的道具的浅浅比较。



现在我们有定义React组件的3种方法:


  1. 不扩展任何类的功能无状态组件

  2. 扩展的组件PureComponent class

  3. 扩展组件的常规组件 class

有些时候,我们曾经将无状态组件称为纯组件,甚至是哑组件。似乎像纯一词的整个定义现在已经在反应中有所变化。



虽然我了解这三者之间的基本差异,但我仍然不确定选择什么。还有哪些性能影响和权衡取决于每一个?






更新:< h3>

这些是我希望得到澄清的问题:




  • 我应该选择定义我的简单组件作为功能(为了简单起见)或扩展 PureComponent 类(为了表现的缘故)?

  • 性能提升我得到一个真正的折中
    简单我失去了?

  • 我将需要扩展正常的组件 class我可以随时使用 PureComponent 来获得更好的表现?


解决方案

您如何决定,根据组件的目的/大小/道具/行为,您如何选择这三个?



扩展从 React.PureComponent 或从 React.Component 与自定义 shouldComponentUpdate 方法有性能暗示附件。使用无状态功能组件是一种架构选择,并且没有任何性能优势(但是)。




  • 对于需要轻松重用的简单的,只有演示文稿的组件,优选无状态功能组件。这样你就可以确定它们与实际的应用程序逻辑脱钩,它们很容易测试,并且没有意外的副作用。例外情况是,如果由于某些原因您有很多或者您真的需要优化其渲染方法(因为您无法定义 shouldComponentUpdate 为无状态功能组件)。


  • 扩展 PureComponent 如果你知道你的输出取决于简单的道具/状态(简单嵌套数据结构,因为PureComponent执行浅比较)并且您需要/可以获得一些性能改进。


  • 扩展组件并实现您自己的 shouldComponentUpdate ,如果您需要通过执行下一个/当前道具和状态之间的自定义比较逻辑来获得性能提升。例如,您可以使用lodash#isEqual快速执行深入的比较:

      class MyComponent extends Component {
    shouldComponentUpdate nextProps,nextState){
    return!_。isEqual(this.props,nextProps)|| !_。isEqual(this.state,nextState);
    }
    }




另外,实现自己的 shouldComponentUpdate 或从 PureComponent 扩展是优化,像往常一样,你应该开始研究只有如果您有性能问题(避免过早优化)。
作为经验法则,我总是尝试在应用程序处于工作状态后进行这些优化,大部分功能已经实现。



更多细节



功能无状态组件



这些只是使用一个函数定义。由于无状态组件没有内部状态,输出(所呈现的内容)仅取决于作为此函数输入的道具。



优点:




  • 反应。如果你不需要管理任何状态,为什么要打扰类和继承?函数和类之间的主要区别之一是使用该函数,您确信输出仅取决于输入(不在之前执行的任何历史记录上)。


  • 理想情况下,在应用程序中,您应该尽可能多地拥有无状态的组件,因为这通常意味着您将逻辑转移到视图层之外,并将其移动到像redux这样的位置,这意味着您可以测试您的真实逻辑不必呈现任何东西(更容易测试,更可重复使用等)。




缺点:




  • 没有生命周期方法。您没有办法定义 componentDidMount 和其他朋友。通常你会在层次结构中的父级组件中做到这一点,所以你可以把所有的孩子都变成无状态的。


  • 需要渲染,因为您无法定义 shouldComponentUpdate 。每次组件接收到新的道具(无法进行浅比较等)时,都会重新渲染。在将来,React可以自动优化无状态组件,现在有一些可以使用的库。由于无状态组件只是功能,基本上是功能记忆的经典问题。


  • 不支持参考: https://github.com/facebook/react/issues/4936




扩展PureComponent类VS的组件扩展Component类的正常组件:



React曾经有一个 PureRenderMixin 可以附加到使用 React.createClass 语法定义的类。 mixin将简单地定义一个 shouldComponentUpdate 执行下一个道具和下一个状态之间的浅比较,以检查是否有任何改变。如果没有更改,那么就不需要执行重新渲染。



如果要使用ES6语法,则不能使用mixin。所以为了方便React引入了一个 PureComponent 类,你可以继承而不是使用组件 PureComponent 以与 PureRendererMixin 相同的方式实现 shouldComponentUpdate 。这主要是一个方便的事情,所以你不必自己实现,因为当前/下一个状态和道具之间的浅比较可能是最常见的情况,可以给你一些快速的胜利。



示例:

  class UserAvatar extends Component {
render(){
返回< div>< img src = {this.props.imageUrl} /> {{this.props.username}}< / div>
}
}

如您所见,输出取决于 props.imageUrl props.username 。如果在父组件中,使用相同的道具呈现< UserAvatar username =fabioimageUrl =http://foo.com/fabio.jpg/> React会每次调用 render ,即使输出完全一样。记住,React实现了dom diffing,所以DOM不会被实际更新。然而,执行dom差异可能是昂贵的,所以在这种情况下,这将是一种浪费。



如果您使 UserAvatar 组件扩展 PureComponent 将执行浅比较,因为道具和nextProps是一样的,所以 render 根本不会被调用。



在React中定义pure的注释:



一般来说,纯函数是一个总是为相同的结果给出相同的输入。输出(对于React,这是由 render 方法返回的)不依赖于任何历史/状态,并且它没有任何副作用(更改在React中,无状态组件根据上面的定义不一定是纯组件,如果你调用无状态一个从不调用的组件 this.setState 并且不使用 this.state



事实上,在$ code> PureComponent 中,您仍然可以在生命周期方法中执行副作用。例如,您可以在 componentDidMount 中发送一个ajax请求,或者您可以执行一些DOM计算,以动态调整 render

Dumb components定义具有更实用的意义(至少在我的理解中):一个愚蠢的组件被告知该怎么做通过一个父组件通过道具,并不知道如何做的事情,而是使用道具回调。



智能的示例 AvatarComponent

  class AvatarComponent extends Component {
expandAvatar(){
this.setState({loading:true});
sendAjaxRequest(...)then then(()=> {
this.setState({loading:false});
});
}

render(){
< div onClick = {this.onExpandAvatar}>
< 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>
}
}

最后我会说笨 无状态和纯粹是完全不同的概念,有时可能重叠,但不一定取决于您的用例。


Came to know that from React v15.3.0, we have a new base class called PureComponent to extend with PureRenderMixin built-in. What I understand is that, under the hood this employs a shallow comparison of props inside shouldComponentUpdate.

Now we have 3 ways to define a React component:

  1. Functional stateless component which doesn't extend any class
  2. A component that extends PureComponent class
  3. A normal component that extends Component class

Some time back we used to call stateless components as Pure Components, or even Dumb Components. Seems like the whole definition of the word "pure" has now changed in React.

Although I understand basic differences between these three, I am still not sure when to choose what. Also what are the performance impacts and trade-offs of each?


Update:

These are the question I expect to get clarified:

  • Should I choose to define my simple components as functional (for the sake of simplicity) or extend PureComponent class (for performance sake)?
  • Is the performance boost that I get a real trade-off for the simplicity I lost?
  • Would I ever need to extend the normal Component class when I can always use PureComponent for better performance?

解决方案

How do you decide, how do you choose between these three based on the purpose/size/props/behaviour of our components?

Extending from React.PureComponent or from React.Component with a custom shouldComponentUpdate method have performance implications. Using stateless functional components is an "architectural" choice and doesn't have any performance benefits out of the box (yet).

  • For simple, presentational-only components that need to be easily reused, prefer stateless functional components. This way you're sure they are decoupled from the actual app logic, that they are dead-easy to test and that they don't have unexpected side effects. The exception is if for some reason you have a lot of them or if you really need to optimise their render method (as you can't define shouldComponentUpdate for a stateless functional component).

  • Extend PureComponent if you know your output depends on simple props/state ("simple" meaning no nested data structures, as PureComponent performs a shallow compare) AND you need/can get some performance improvements.

  • Extend Component and implement your own shouldComponentUpdate if you need some performance gains by performing you custom comparison logic between next/current props and state. For example, you can quickly perform a deep comparison using lodash#isEqual:

    class MyComponent extends Component {
        shouldComponentUpdate (nextProps, nextState) {
            return !_.isEqual(this.props, nextProps) || !_.isEqual(this.state, nextState);
        }
    }
    

Also, implementing your own shouldComponentUpdate or extending from PureComponent are optimizations, and as usual you should start looking into that only if you have performance issues (avoid premature optimizations). As a rule of thumb, I always try to do these optimisations after the application is in a working state, with most of the features already implemented. It's a lot easier that way to focus on performance problems only when they actually get in the way.

More details

Functional stateless components:

These are defined just using a function. Since there's no internal state for a stateless component, the output (what's rendered) only depends on the props given as input to this function.

Pros:

  • Simplest possible way of defining a component in React. If you don't need to manage any state, why bothering with classes and inheritance? One of the main differences between a function and a class is that with the function you are sure the output depends only on the input (not on any history of the previous executions).

  • Ideally in your app you should aim to have as many stateless components as possible, because that normally means you moved your logic outside of the view layer and moved it to something like redux, which means you can test your real logic without having to render anything (much easier to test, more reusable, etc.).

Cons:

  • No lifecycle methods. You don't have a way to define componentDidMount and other friends. Normally you do that within a parent component higher in the hierarchy so you can turn all the children into stateless ones.

  • No way to manually control when a re-render is needed, since you can't define shouldComponentUpdate. A re-render happens every time the component receives new props (no way to shallow compare, etc.). In the future, React could automatically optimise stateless components, for now there's some libraries you can use. Since stateless components are just functions, basically it's the classic problem of "function memoization".

  • Refs are not supported: https://github.com/facebook/react/issues/4936

A component that extends PureComponent class VS A normal component that extends Component class:

React used to have a PureRenderMixin you could attach to a class defined using React.createClass syntax. The mixin would simply define a shouldComponentUpdate performing a shallow comparison between the next props and the next state to check if anything there changed. If nothing changes, then there's no need to perform a re-render.

If you want to use the ES6 syntax, you can't use mixins. So for convenience React introduced a PureComponent class you can inherit from instead of using Component. PureComponent just implements shouldComponentUpdate in the same way of the PureRendererMixin. It's mostly a convenience thing so you don't have to implement it yourself, as a shallow comparison between current/next state and props is probably the most common scenario that can give you some quick performance wins.

Example:

class UserAvatar extends Component {
    render() {
       return <div><img src={this.props.imageUrl} /> {{ this.props.username }} </div>
    }
} 

As you can see the output depends on props.imageUrl and props.username. If in a parent component you render <UserAvatar username="fabio" imageUrl="http://foo.com/fabio.jpg" /> with the same props, React would call render every time, even if the output would be exactly the same. Remember though that React implements dom diffing, so the DOM would not be actually updated. Still, performing the dom diffing can be expensive, so in this scenario it would be a waste.

If you make the UserAvatar component extends PureComponent instead, a shallow compare would be performed and because props and nextProps are the same, render would not be called at all.

Notes on the definition of "pure" in React:

In general, a "pure function" is a function that evaluates always to the same result given the same input. The output (for React that's what's returned by the render method) doesn't depend on any history/state and it doesn't have any side-effects (operations that change the "world" outside of the function).

In React, stateless components are not necessarily pure components according to the definition above if you call "stateless" a component that never calls this.setState and that doesn't use this.state.

In fact, in a PureComponent, you can still perform side-effects during lifecycle methods. For example you could send an ajax request inside componentDidMount or you could perform some DOM calculation to dynamically adjust the height of a div within render.

The "Dumb components" definition has a more "practical" meaning (at least in my understanding): a dumb component "gets told" what to do by a parent component via props, and doesn't know how to do things but uses props callbacks instead.

Example of a "smart" AvatarComponent:

class AvatarComponent extends Component {
    expandAvatar () {
        this.setState({ loading: true });
        sendAjaxRequest(...).then(() => {
            this.setState({ loading: false });
        });
    }        

    render () {
        <div onClick={this.onExpandAvatar}>
            <img src={this.props.username} />
        </div>
    }
}

Example of a "dumb" AvatarComponent:

class AvatarComponent extends Component {
    render () {
        <div onClick={this.props.onExpandAvatar}>
            {this.props.loading && <div className="spinner" />}
            <img src={this.props.username} />
        </div>
    }
}

In the end I would say that "dumb", "stateless" and "pure" are quite different concepts that can sometimes overlap, but not necessarily, depending mostly on your use case.

这篇关于反应功能无状态组件,PureComponent,Component;有什么区别,何时应该使用什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆