4

[译] 可呈现组件和容器组件

可呈现组件和容器组件

原文地址 here

我在写React应用的时候发现了一种非常有用的简单的模式。当然如果你已经开发了一段时间的React应用,

那么你可能已经发现了这种模式。这篇文章已经很好的解释它了,但是我还是想添加一些我的观点。

如果你将你的组件分为两种类型,那么它将会更加合理和方便。我称他们为容器呈现组件,

当然我也听过 其他的名字比如胖和瘦,智能和死板,有状态的和纯函数的,屏幕和组件等等。虽然看起来不太一样,

但是其实核心内容使一样的。

我所说的呈现组件如下:

- 与事情的呈现(看起来)有关
- 可能同时包含可呈现组件和容器组件在里面,并且通常有他们自己的**DOM**标记和自己的样式
- 通常允许包含通过应用 `this.props.children`
- 不依赖于应用的其他部分,像`Flux actions` 或者 `stores`
- 不定义数据使如何加载和改变的
- 接收数据和显示回调通过引用`props`
- 几乎没有他们自己的状态(即使他们有,那么也是UI状态而不是数据)
- 由[函数式组件](https://facebook.github.io/react/blog/2015/10/07/react-v0.14.html#stateless-functional-components)写成除非他们需要状态,生命周期的钩子,或者是性能优化
- 例子:页面,侧边栏,故事,用户信息,列表

我所说的容器组件如下:

- 与事情的运行有关
- 可能同时包含可呈现组件和容器组件但是通常不包含任何**DOM**标记除了一些`divs`,不会有任何样式
- 为其他的可呈现组件或者其他的容器组件提供数据和操作
- 调用`Flux actions` 并且把这些`actions`作为回调提供给可呈现组件
- 通常由[高优先级的组件](https://medium.com/@dan_abramov/mixins-are-dead-long-live-higher-order-components-94a0d2f9e750)
像`connect()/React Redux`,`createContainer()/Relay`或者`Container.create()/Flux`生成而不是手写
- 例子:UserPage, FollowersSidebar, StoryContainer, FollowedUserList

这种模式的益处

- 关注点的分离。可以更好的理解你的app和UI通过写这样的组件用这样的方式
- 更好的可重用性。你可以让相同的呈现组件与不同的数据源相结合,
然后将这些数据源放到不同的容器当中已备将来使用
- 呈现组件是你的调色板,你可以将他们放在一个单页面然后让设计师做他们自己的改变,
而不用接触整个app的逻辑,你可以运行回归测试在这个页面
- 这种模式迫使你提取样式组件像 Sidebar, Page, ContextMenu 并且
通过`this.props.children`这样的引用而不是复制相同的标记和样式到好几个不同的容器

要牢记,组件不一定散发DOM,他们仅仅需要提供必要的分界组合在UI关心的地方

好好利用它

什么时候引入容器

我建议你开始构建你的app的时候仅仅包含呈现组件.最终你会意识到你传入了太多的props给那些集成组件。

当你注意到有些组件没有使用他们接收到的props而仅仅是转发了它们的时候,并且你必须重新连接这些中间级组件,

任何时候,子组件都需要数据的时候,那么这个时候就是引入一个容器的时候。这样你可以获得这些数据并且修改这些叶子组件的props

而不用担心树中不相关的组件。

很显然,这是一个不断重构的过程,所以不要尝试一次性将这个东西做好。当你探索这种模式的时候,

你将会对什么时候它应该提取这些容器,就像你知道什么时候它需要提取出一个函数一样。

我的Redux系列可能会帮助到你。

其他的一些对立单词

明白这点很重要,可呈现组件和容器组件的区别不是技术上的不同,它仅仅是为了达到区分他们这个目的。

作为对比,这里也有一些相关(但是不相同)的技术区别:

  • 有状态的和无状态. 有些组件使用React setState() 方法但是有一些不使用。
    尽管容器组件通常是有状态的而呈现组件通常是无状态的,但是这个不是一个硬性要求。
    呈现组件可以是有状态的而容器组件也可以是有状态的。

  • 类和函数。 从React 0.14 以后,
    组件就可以同时备声明为函数或者类。函数生成的组件易于定义但是缺少特定的仅对当前类组件可用的特性。
    这些特性限制可能会在急急急即将来被解决但是他们目前仍存在。因为函数式组件是易于理解的,
    我建议你使用他们除非你需要状态,生存周期的钩子或者是性能优化这些问题。当然,这些问题仅仅对类组件是可用的到到目前为止。

  • 函数式和非函数式。人们通常说一个组件式函数式的如果它保证返回相同的结果只要给了相同的props , state
    纯函数式组件可以被定义为类或者函数式,并且可以式有状态的或者无状态的。函数式组件的另外一个重要的层面式他们不依赖于props state的深度变化,
    因此他们渲染性能可以被优化通过一个浅显的对比关于shouldComponentUpdate hook的。

呈现组件和状态组件可以落入这些对立单词中的任意一个。在我以往的经验中,呈现组件常常是无状态的纯函数,

而容器组件常常是有状态的纯类组件。然而这并不是一条规则,只是一种直觉。我曾经看到过一个完全相反的例子,

当然也只是在特定的环境下才产生的。

不要教条式地认为呈现组件和容器组件是完全分离地,有时候是很难区分出他们的。如果你不确定他们们应该是哪一种组件,

也许是还不到时候。不要慌!

例子

this gistMichael Chan 相当不错地解释了这个问题。

相关阅读

[笔记] PHP源码-01