Presentational and Container Components
https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0
There’s a simple pattern I find immensely useful when writing React applications. If you’ve been doing React for a while, you have probably already discovered it. This article explains it well, but I want to add a few more points.
You’ll find your components much easier to reuse and reason about if you divide them into two categories. I call them Container and Presentational components* but I also heard Fat and Skinny, Smart and Dumb, Stateful and Pure, Screens and Components, etc. These all are not exactly the same, but the core idea is similar.
My presentational components:
- Are concerned with how things look.
- May contain both presentational and container components** inside, and usually have some DOM markup and styles of their own.
- Often allow containment via this.props.children.
- Have no dependencies on the rest of the app, such as Flux actions or stores.
- Don’t specify how the data is loaded or mutated.
- Receive data and callbacks exclusively via props.
- Rarely have their own state (when they do, it’s UI state rather than data).
- Are written as functional components unless they need state, lifecycle hooks, or performance optimizations.
- Examples: Page, Sidebar, Story, UserInfo, List.
My container components:
- Are concerned with how things work.
- May contain both presentational and container components** inside but usually don’t have any DOM markup of their own except for some wrapping divs, and never have any styles.
- Provide the data and behavior to presentational or other container components.
- Call Flux actions and provide these as callbacks to the presentational components.
- Are often stateful, as they tend to serve as data sources.
- Are usually generated using higher order components such as connect()from React Redux, createContainer() from Relay, or Container.create() from Flux Utils, rather than written by hand.
- Examples: UserPage, FollowersSidebar, StoryContainer, FollowedUserList.
I put them in different folders to make this distinction clear.
Benefits of This Approach
- Better separation of concerns. You understand your app and your UI better by writing components this way.
- Better reusability. You can use the same presentational component with completely different state sources, and turn those into separate container components that can be further reused.
- Presentational components are essentially your app’s “palette”. You can put them on a single page and let the designer tweak all their variations without touching the app’s logic. You can run screenshot regression tests on that page.
- This forces you to extract “layout components” such as Sidebar, Page, ContextMenu and use this.props.children instead of duplicating the same markup and layout in several container components.
Remember, components don’t have to emit DOM. They only need to provide composition boundaries between UI concerns.
Take advantage of that.
When to Introduce Containers?
I suggest you to start building your app with just presentational components first. Eventually you’ll realize that you are passing too many props down the intermediate components. When you notice that some components don’t use the props they receive but merely forward them down and you have to rewire all those intermediate components any time the children need more data, it’s a good time to introduce some container components. This way you can get the data and the behavior props to the leaf components without burdening the unrelated components in the middle of the tree.
This is an ongoing process of refactoring so don’t try to get it right the first time. As you experiment with this pattern, you will develop an intuitive sense for when it’s time to extract some containers, just like you know when it’s time to extract a function. My free Redux Egghead series might help you with that too!
Other Dichotomies
It’s important that you understand that the distinction between the presentational components and the containers is not a technical one. Rather, it is a distinction in their purpose.
By contrast, here are a few related (but different!) technical distinctions:
- Stateful and Stateless. Some components use React setState() method and some don’t. While container components tend to be stateful and presentational components tend to be stateless, this is not a hard rule. Presentational components can be stateful, and containers can be stateless too.
- Classes and Functions. Since React 0.14, components can be declared both as classes and as functions. Functional components are simpler to define but they lack certain features currently available only to class components. Some of these restrictions may go away in the future but they exist today. Because functional components are easier to understand, I suggest you to use them unless you need state, lifecycle hooks, or performance optimizations, which are only available to the class components at this time.
- Pure and Impure. People say that a component is pure if it is guaranteed to return the same result given the same props and state. Pure components can be defined both as classes and functions, and can be both stateful and stateless. Another important aspect of pure components is that they don’t rely on deep mutations in props or state, so their rendering performance can be optimized by a shallow comparison in their shouldComponentUpdate() hook. Currently only classes can define shouldComponentUpdate() but that may change in the future.
Both presentational components and containers can fall into either of those buckets. In my experience, presentational components tend to be stateless pure functions, and containers tend to be stateful pure classes. However this is not a rule but an observation, and I’ve seen the exact opposite cases that made sense in specific circumstances.
Don’t take the presentational and container component separation as a dogma. Sometimes it doesn’t matter or it’s hard to draw the line. If you feel unsure about whether a specific component should be presentational or a container, it might be too early to decide. Don’t sweat it!
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
Footnotes
* In an earlier version of this article I called them “smart” and “dumb” components but this was overly harsh to the presentational components and, most importantly, didn’t really explain the difference in their purpose. I enjoy the new terms much better, and I hope that you do too!
** In an earlier version of this article I claimed that presentational components should only contain other presentational components. I no longer think this is the case. Whether a component is a presentational component or a container is its implementation detail. You should be able to replace a presentational component with a container without modifying any of the call sites. Therefore, both presentational and container components can contain other presentational or container components just fine.
Presentational and Container Components的更多相关文章
- [Redux] Extracting Container Components (FilterLink)
Learn how to avoid the boilerplate of passing the props down the intermediate components by introduc ...
- (翻译)React Container Components
原文:Container Components Container Components 在 React 模式上对我的代码有最深远影响的一个模式叫 container component 模式. 在 ...
- (翻译) Container Components
react.js javascript 这篇文章翻译自Medium的一篇文章:Container Components 选择这篇文章翻译的原因是,在刚接触React的时候,这篇文章很好的指引我了解 ...
- [Redux] Extracting Container Components -- Complete
Clean TodoApp Component, it doesn't need to receive any props from the top level component: const To ...
- [Redux] Redux: Extracting Container Components -- AddTodo
Code to be refactored: const AddTodo = ({ onAddClick }) => { let input; return ( <div> < ...
- [Redux] Extracting Container Components -- VisibleTodoList
Code to be refacted: const TodoList = ({ todos, onTodoClick }) => ( <ul> {todos.map(todo =& ...
- 【原创】Redux 卍解
Redux 卍解 Redux - Flux设计模式的又一种实现形式. 说起Flux,笔者之前,曾写过一篇<ReFlux细说>的文章,重点对比讲述了Flux的另外两种实现形式:『Facebo ...
- React + Redux 入坑指南
Redux 原理 1. 单一数据源 all states ==>Store 随着组件的复杂度上升(包括交互逻辑和业务逻辑),数据来源逐渐混乱,导致组件内部数据调用十分复杂,会产生数据冗余或者混用 ...
- [react] 细数 React 的原罪
Props & onChange 的原罪 .「props & onChange 接口规范」它不是一个典型的「程序接口规范」. 当你拿到一个可视组件的 ref,却没有类似 setProp ...
随机推荐
- Centos7.4和Ubuntu18.04安装PHP7.2
安装依赖 yum install gcc-c++ libxml2 libxml2-devel openssl openssl-devel bzip2 bzip2-devel libcurl libcu ...
- Makefile 和 CMakeLists.txt
Makefile Makefile 的格式 target: prerequisites [tab]command 例子 #Makefile all:chap1 chap2 chap1: - - - : ...
- android.database.sqlite.SQLiteException: near "FROM"
07-20 00:19:30.496: E/JavaBinder(6807): *** Uncaught remote exception! (Exceptions are not yet su ...
- ios中广告滚动页面(uiscrollview)
展示功能 第一步 引入 “EScrollerView.h”,EScrollerView.m"文件 用法 NSArray *imgarr=@[@"1.jpg",@" ...
- ubuntu_thunder
Thunder 出自Ubuntu中文 File:Http://forum.ubuntu.org.cn/download/file.php?id=123020&mode=view/wine-th ...
- iOS 用自签名证书实现 HTTPS 请求的原理
在16年的WWDC中,Apple已表示将从2017年1月1日起,所有新提交的App必须强制性应用HTTPS协议来进行网络请求.默认情况下非HTTPS的网络访问是禁止的并且不能再通过简单粗暴的向Info ...
- Jetty使用内存过大的解决方案
之前用Jetty做过一个消息通知服务器,主要功能就是其他各个子系统如果有需要push给客户端消息的就把这个消息发给我的Server,我用WebSocket来推送给客户端~ 程序上线一段时间之后运维工程 ...
- JAVA操作mysql
所需jar包:mysql-connector-java.jar 代码: import java.sql.*; import java.util.ArrayList; import java.util. ...
- ruby的sort方法的重新认识
ruby中的sort方法,这个方法可以加一个两个参数的block,这个block可以返回1 0 -1来表示这两个参数大于 等于 小于示例: str = ["192.160.175" ...
- 树莓派进阶之路 (012) - 关于Raspberry Pi树莓派无线网卡配置
Raspberry Pi树莓派无线网卡配置[多重方法备选] 要想让树莓派方便操作,肯定需要配置无线网卡,这样可以大大增强树莓派的移动性和便利性,其实配置无线网卡基本就是和普通linux平台下配置无线网 ...