原文:Presentational and Container Components
image.png

Presentational 组件

  • 和UI有关
  • 可能包含presentationalcontainer组件,通常有DOM标记或者本身的样式信息。
  • 允许通过 this.props.children传入内容。
  • 没有对项目中其他的依赖,例如Fluxactions 和stores。
  • 不会指定数据是如何加载或者变更的。
  • 分别通过props接受数据和回调函数。
  • 很少有自身的state()
  • 一般是函数式组件的形式除非他们需要state,声明周期钩子,或者性能优化。
  • 例如:Page, Sidebar, Story, UserInfo, List.

Container组件

  • 和行为/逻辑有关系。
  • 可能包含presentationalcontainer组件,但是没有DOM标记,除了一个包装div,没有任何的样式信息。
  • presentational组件或者其他的container组件提供行为和数据。
  • 调用Flux/Reduxactions,提供回调函数给presentational组件。
  • 有状态的,作为数据源的提供者。
  • 一般是通过高阶组件的方式生成,例如React Redux的connect()方法,Relay的createContainer(),Flux的Container.create()方法。
  • 示例:UserPage, FollowersSidebar, StoryContainer, FollowedUserList.

Benefits of This Approach


  • 更好的关注点分离。更好的理解你的应用和UI,通过这种方式。
  • 更好的复用性。可以把相同的presentational组件应用在不同的container组件里,也可以应用不同的数据源。
  • Presentational组件是应用的‘调色板’。你可以把他们放在一个单独的页面,让设计者调整它们的变量,而不需要修改应用的逻辑。你可以在这个页面进行快照回归测试。
  • 这会强迫你抽取‘layout component’例如Sidebar, Page, ContextMenu,在一些container组件里this.props.children来代替复制相同的标记。

记住,组件不是来生成DOM。他们只是在**_UI_**关注点之间提供组合边界。

什么时候引入Container?

我建议你一开始构建应用的时候,先从presentational组件开始。最终你会发现你传递了太多的props给中间组件。当你注意到很多的组件并不需要一些接收到的props,仅仅是向下转发,你需要重新连接这些中间组件,而子组件需要更多的数据,这个时候你就要考虑引入一些container组件了。这种方式你可以把包含数据和行为的props传递给叶子组件,而不需要给组件结构树中间的组件增加负担,传递不需要的props

重构是实时进行的,没必要第一次就把它做对。随着体会到这种模式的好处,你会开发出一种直觉就是知道何时去抽取container,就像你知道该何时去抽取函数一样。

其他的分类

这是非常重要的,理解presentational组件和container组件之间的区别并不是技术上的区别。而是使用目的上的区别。

相比之下,也会有一些技术上的差别:

  • 有状态和无状态。一些组件会用到React setState()方法而其他的则用不到。container组件一般是有状态的,而presentational一般是无状态的,但这没有严格的限制。presentational组件也可以是有状态的,而container组件可以是无状态的。

  • 类组件和函数组件。自从React0.14的发布,组件既可以被声明为函数组件也可以是类组件。函数式组件定义比较简单,但是缺乏一些必要的特性,目前只是应用在类组件里。由于函数式组件是易于理解的,应该在项目中尽可能多的使用他们。

  • 纯组件和非纯组件。组件是纯洁的当给予相同的propsstate,它保证返回相同的结果。纯组件可以是类组件也可以是函数组件,也可以是有状态的也可以是无状态的。对于纯洁组件另一个重要的方面是不依赖于propsstate深度变更,所以他们的渲染性能可以通过浅层比较优化通过shouldComponentUpdate钩子方法实现。

PresentationalContainer组件可以是两者皆可的。从我的经验,Presentational组件通常是无状态纯函数组件,Container组件通常是有状态纯Class组件。

其他参考: