转载自 Dan Abramov. Presentational and Container Components. Mar 23, 2015
在编写React应用时,有一个简单的模式我觉得非常有用。如果你已经做了一段时间的React,你可能已经发现了它。这篇文章很好地解释了它,但我想再补充几点。
如果你把你的组件分为两类,你会发现你的组件更容易重用和推理。我把它们称为容器Container
和展示Presentational
型组件*,但我也听说过 Fat 和 Skinny,Smart 和 Dumb,Stateful和 Pure,Screen 和 Component等。这些都不完全相同,不过核心思想是相似的。
我对展示型组件的理解:
- 关注的是事物的外观。
- 内部可能同时包含展示和容器组件**,通常有自己的一些DOM标记和样式。
- 通常允许通过
this.props.children
进行包含。 - 对应用的其他部分没有依赖性,比如Flux动作或商店。
- 不要指定数据的加载或突变方式。
- 只通过props来接收数据和回调。
- 很少有自己的状态(即使有,也是UI状态而不是数据)。
- 除非它们需要状态、生命周期钩子或性能优化,否则应被写成函数组件(functional components)。
- 例如:页面、边栏、故事、用户信息、列表。
我对容器型组件的理解:
- 关注的是事物如何工作。
- 内部可能同时包含展示和容器组件**,但除了一些包装div外,通常没有自己的任何DOM标记,也从来没有任何样式。
为presentational或其他容器组件提供数据和行为。
- 调用 Flux 动作,并将这些动作作为回调提供给展示组件。
- 通常是有状态的,因为它们往往作为数据源。
- 通常使用更高阶的组件生成,如React Redux的
connect()
、Relay的createContainer()
或Flux Utils的Container.create()
,而不是手工编写。 - 例如:UserPage, FollowersSidebar, StoryContainer, FollowedUserList.
我把它们放在不同的文件夹里,以明确这种区别。
这种方法的好处
- 更好的分离关注点。通过这种方式编写组件,您可以更好地理解您的应用程序和您的UI。
- 更好的重用性。你可以用完全不同的状态源来使用相同的表现型组件,并将其转化为可以进一步重用的独立容器组件。
展示型组件本质上就是你的应用的 "调色板"。你可以把它们放在一个页面上,让设计师调整它们的所有变化,而不触及应用的逻辑。你可以在该页面上运行截图回归测试。
- 这迫使你提取 "布局组件",如Sidebar,Page,ContextMenu,并使用
this.props.children
,而不是在几个容器组件中重复相同的标记和布局。
请记住,组件不一定要操作DOM。它们只需要提供UI关注点之间的组成边界。 利用好这一点。
什么时候引入容器?
我建议你先只用展示组件开始构建你的应用。最终你会意识到,你把太多的道具传递给了中间的组件。当你注意到有些组件并没有使用它们接收到的道具,而只是将它们转发下去,而且当子组件需要更多数据时,你必须随时重新连接所有这些中间组件,这就是引入一些容器组件的好时机。这样你就可以把数据和行为道具送到叶子组件上,而不会给树中间的不相关组件造成负担。 这是一个不断重构的过程,所以不要试图第一次就把它做好。当你尝试这种模式时,你会对什么时候该提取一些容器有一种直观的感觉,就像你知道什么时候该提取一个函数一样。我的free Redux Egghead系列或许也能帮到你!
其他划分法
重要的是,你要明白,展示性组件和容器之间的区别不是技术上的区别。而是它们的目的的区别。 相比之下,这里有几个相关(但不同!)的技术区别。
-
有状态和无状态。有些组件使用
React setState()
方法,有些不使用。虽然容器组件倾向于有状态,而呈现型组件倾向于无状态,但这并不是一个硬性规则。呈现型组件可以是有状态的,容器也可以是无状态的。 -
类和函数。从React 0.14开始,组件既可以声明为类,也可以声明为函数。函数式组件的定义更简单,但它们缺乏某些目前只有类组件才有的功能。其中一些限制可能会在未来消失,但它们今天仍然存在。因为功能组件更容易理解,我建议你使用它们,除非你需要状态、生命周期钩子或性能优化,这些功能目前只有类组件才有。
-
纯粹和不纯粹。人们说,如果一个组件能保证在相同的道具和状态下返回相同的结果,那么这个组件就是纯粹的。纯组件既可以定义为类,也可以定义为函数,既可以有状态,也可以无状态。纯组件的另一个重要方面是它们不依赖于道具或状态的深度突变,因此它们的渲染性能可以通过在其
shouldComponentUpdate()
钩子中进行浅层比较来优化。目前只有类可以定义shouldComponentUpdate()
,但未来可能会改变。
呈现型组件和容器都可以归入这两种类型。根据我的经验,呈现型组件往往是无状态的纯函数,而容器往往是有状态的纯类。然而这并不是一个规则,而是一个观察结果,我也看到过在特定情况下完全相反的情况,这是有道理的。 不要把有状态和容器组件分离当成教条。有时候这并不重要,或者说很难划清界限。如果你觉得不确定某个特定的组件应该是呈现性的还是容器的,那么现在决定可能还为时过早。不要紧张!
Example
This gist by Michael Chan pretty much nails it.
Further Reading
Getting Started with Redux Mixins are Dead, Long Live Composition Container Components Atomic Web Design Building the Facebook News Feed with Relay
注
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!