这是篇文章翻译自medium的:Presentational and Container Components
译者语:
这篇文章是紧接着对我上一篇翻译的扩充,对Container Component模式描述的更加细,解决了我很多开发中的困惑。
Presentational and Container Components
在我写React程序的时候,我发现一个模式非常的好用。对React有一定经验的人,肯定已经对这个模式有过了解。这篇文章已经做了很好的介绍,但是在这里我想要再补充几点。
当你把你的组件分成两种不同的类型,你会发现他们会非常容易复用和理解。这两种类型,我称为Container and Presentational components(译者:可翻译为容器和展示组件,因为社区中常以英文名字出现,所以不翻译)。当然,我也听过Fat and Skinny, Smart and Dumb, Stateful and Pure, Screens and Components等等,这些东西虽然不完全相同,但是他们的中心思想是一样的。
Presentational components:
关注于该怎样展现
中间或许会包含presentational和container组件,同时也可以包含自己的一些JSX代码和样式代码
允许通过this.props.children来传递内容
不和app的其他地方产生依赖关系,比如没有Flux的actions、stores
不关注数据是怎么加载和处理的
只通过props来获取数据和回掉函数
一般没有自己的state(即使有,也只是UI状态,而不是数据)
除非组件需要state,生命周期或者性能优化,可以使用functional components的方式进行声明
举个栗子:Page, Sidebar, Story, UserInfo, List
Container components:
关注与该怎么运行
中间可以包含presentational和container组件,除非包裹用的div的一些样式,一般不会含有任何样式
向包含的presentational和其他的container components传递数据和行为方法
调用Flux的actions或者把这些actions作为回掉函数传给presentational components
由于他们经常作为数据来源的角色,所以container一般会包含state
一般会由更高等级的components来生成,比如React Redux的connect(), Relay的createContainer(), Flux Utils的Container.create()
举个栗子:UserPage, FollowersSidebar, StoryContainer, FollowedUserList
通常,我会把它们放到不同的文件夹下面,以便区分。
这么做的好处
职责分离。这样你会更容易理解你的app和UI。
更易复用。同一个presentational component,也可以被用在不同的数据源下。
presentational component可以作为一个“调色板”。你可以把它放在一个页面上,让设计师在不需要知道app逻辑的情况下,随意改变相关变量。
这样做可以强迫你写一些“布局组件”,比如Sidebar, Page, ContextMenu,然后通过this.props.children来传递内容,而不是在不同的container中写一大堆相同的代码。
为什么要使用Containers
我首先建议你先不使用这个模式来搭建你的app,最后发现你会传递太多的props给中间组件。对于很多中间组件来说,他们并不需要这些props,但是他们还必须传递给下一级组件。同时,如果下级组件需要增加一个数据,那么你就需要一路修改到最上面。这个时候,就是你需要引入Container and Presentational component的时候。这样子根组件就可以获得需要的数据和行为方法,而不会去修改那些没有关系的中间组件。
不要期望你刚开始就能把两种组件做出正确的区分。当你获得更多的经验,你就会知道该什么时候用container什么时候用presentational组件,就像你知道什么时候要声明一个function一样。这个免费的教程可以帮助你。
一些词汇
你需要明白,container和presentational components的不同并不是技术上的不同,而是目的上的不同。
作为对比,这里列出一些词汇:
Stateful and Stateless 有一些组件使用React.setState()方法,有些不需要用。Container更倾向于Stateful,而Presentational更倾向于Stateless,当然这并不是绝对的。Presentational可以使Stateless,Container也可以是Stateful
Classes and Functions 一个组件可以通过class和function进行声明。Functional components更简洁一些,他们缺少很多class含有的功能。这些或许以后会有改变,但是现在确实存在。由于functional components比较容易理解,所以我建议你使用functional components, 除非你需要state, 生命周期和性能优化这些只有class开放的功能.
Pure and Impure如果相同的props和state,会返回相同的结果,那么这个component就是pure的。Pure组件可以用class或function来声明,他也可以是stateful的,也可以是stateless的。另外一个重要的区别是,pure组件并不依赖于深层的props和state,所以他们可以通过在shouldComponentUpdate()中浅层对比来进行优化。现在这个方法只在class中存在,或许以后会加入到function中。
Presentational和Container组件都可以是任意的一种状态。根据我的经验,presentational组件倾向于stateles pure functions, 而container更倾向于stateful pure classes。当然这只是基于观察得出的结果,我也曾经看到过完全不同的情况。
记住,不要把presentational和container区分的那么明显。有的时候很难去画出一个分界线来。如果你不确定一个组件应该是presentational还是container,那么或许还太早去区分它。
结束语
在早期的文章中,我说presentaional container只能包含presentational components。现在我并不这么认为。
这是篇文章翻译自medium的:Presentational and Container Components