【译】展示型组件和容器型组件(作者:Dan Abramov,Redux的开发者)

本文译自
Presentational and Container Components,文章的作者是
Dan Abramov,他同时也是Redux和Create React App的作者。

在实际使用React + Redux 技术栈的开发过程中,非常好的理解了容器型组件和展示型组件的概念是开发出易维护,可复用React App的基础

在开发React应用的时候,我发现了一种极其简单的开发模式。如果你已经用过一段时间的React,你也许已经发现了它。这篇文章已经讲的很好了,但是我想补充几点。

如果你将组件分为两类,你会发现它们更容易被复用和理解。我把这两类称为容器型组件展示型组件 ,但是我也听说过其他名字,比如臃肿型组件简单型组件智能型组件傻瓜型组件有状态组件纯组件封装型组件元组件等等。它们不完全相同,但是在核心观点上是相似的。

展示型组件

  • 关心数据的展示方式
  • 内部可能包含展示型组件和容器型组件,并且通常存在其他DOM元素及其样式
  • 允许通过this.props.children控制组件
  • 不依赖app中的其它文件,像Flux的actions或stores
  • 不关心数据是如何加载和变化的
  • 仅通过props接收数据和回调函数
  • 几乎不用组件内的state(如果用到的话,也仅仅是维护UI状态而不是数据状态)
  • 除非需要用到state,生命周期函数或性能优化,通常写成函数式组件
  • 例如:Page,Sidebar,Story,UserInfo,List

容器型组件

  • 关心数据的运作方式
  • 内部可能包含展示型组件和容器型组件,但是通常没有任何用于自身的DOM元素,除了一些用于包裹元素的div标签,并且不存在样式
  • 为展示型组件和容器型组件提供数据和操作数据的方法
  • 调用Flux actions并以回调函数的方式给展示型组件提供actions
  • 通常是有状态的,并且作为数据源存在
  • 通常由高阶函数生成例如React Redux的connect(),Realy的createContainer,或者Flux Utils的Container.create(),而不是手写的
  • 例如:UserPage,FollowersSidebar,StoryContainer,FollowedUserList

为了清晰的区分这两种组件,我把放在不同的文件夹中

这种方法的优势

  • 关注点分离。通过用这种方式开发组件,你可以更好的理解你的app和UI
  • 更好的复用性。你可以在不同的数据源中使用相同的展示型组件,也可以把它们放进不同容器型组件中更进一步的进行复用
  • 展示型组件是你的app必不可少的”调色板”,你可以把它们放在一个独立的页面中,让设计师随意拖拽它们的变量而不改变应用的逻辑。在这个页面上进行页面快照回归测试
  • 这种方法逼你去把用于布局的组件抽出来,例如SidebarPageContextMenu。然后通过子组件的方式引入而不是在各个容器型组件中复制粘贴已有的样式和布局

记住,组件不一定要输出DOM元素,它们只需要提供UI之间的组合关系和分界

好好利用这一点

什么时候引入容器?

我建议你先用展示型组件搭建你的app。最终你会意识到你给中间的组件传递了太多的props。有些组件并不使用这些props,而仅仅向下传递。并且当下层组件需要更多数据的时候,你必须重写改写所有的中间组件。这时候就需要引入一些容器型组件。通过这种方式,你可以从叶子节点组件获取数据和方法,而不用考虑处于中间的组件。

这需要边开发边重构,所以没有必要一次做对。随着日常应用这种模式,你会组件培养出一种『这时候我该抽出一个Container』的直接,就像你已经知道什么时候应该提取出一个函数一样。我的Redux教程可能也会帮你一把

其他的二分法

展示型组件和容器型组件这种分类并非十分严格,这是按照它们的目的进行分类。

为了与之前的概念做比较,这是一些相关但不同的二分法

  • 有状态和无状态 有些组件使用React的setState()方法,有些不用。容器型组件往往是有状态的而展示型组件往往是无状态的,这并不是一条铁律。展示型组件也可以是有状态的,容器型组件也可以是无状态的
  • 类和函数 从React0.14开始,组件既可以声明为类也可以声明为函数。函数式组件可以定义的更简单但是也缺少一些只能在类组件中使用的特写。有些限制可能未来会消除,但是在当下仍然是存在的。由于函数式组件更加易于理解,所以我建议你尽量的使用它。除非你需要state,生命周期函数,或者性能优化,这些特性只有在类组件中才可以使用。
  • 纯和非纯 如果一个组件在输入相同props的情况下总是输出相同的结果,那我们称这个组件为pure component。pure component既可以声明为类组件也可以声明为函数式组件,即可以是有状态的也可以是无状态的。另一个重要的方面是,pure component不依赖propsstate的深层比对,所以可以在shouldComponentUpdate方法中进行浅比较优化性能,但是在未来可能有很多变化。

展示型组件和容器型组件都可以放进以上任何一种二分法中。在我看来,展示型组件往往是无状态的纯函数组件,容器型组件往往是有状态的纯类组件。然而这并不是一种要求,而是一种现象,并且在一些特定的场景中我也确实见过完全相反的情况。

不要把展示型组件和容器型组件的划分当成教条。有的时候没有必要对二者进行区分。如果你不太确定一个组件是展示型组件还是容器型组件,也许现在还不是区分它的时候,别太心急!

例子

Michael Chan为我们用一个gist阐释了上面的道理

延伸阅读

    原文作者:GarinZhang
    原文地址: https://segmentfault.com/a/1190000013670158
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞