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 ...
随机推荐
- where 1=1和 0=1 的作用
where 1=1; 这个条件始终为True,在不定数量查询条件情况下,1=1可以很方便的规范语句. 一.不用where 1=1 在多条件查询中的困扰 举个例子,如果您做查询页面,并且,可查询的选项有 ...
- 一个成功的 Git 分支模型
在这篇文章中介绍的开发模型在大约一年前已经在我的私有项目和工作引入的,而且已经被证明是非常成功的.我想写一些关于这个模型的东西已经好一段时间了,但是一直苦于没有时间,不过现在可以了.我不想探讨任何项目 ...
- 利用Git进行团队协作
前言: 这里简单介绍一下Git的历史. 同生活中的许多伟大事件一样,Git 诞生于一个极富纷争大举创新的年代.Linux 内核开源项目有着为数众广的参与者.绝大多数的 Linux 内核维护工作都花在了 ...
- 在QTableView中某列中添加Button的导致滚动条滚动的时候消失的问题
之前在项目上需要在表格中加入Button是按照以下两个文章的做法: http://www.cnblogs.com/li-peng/p/3961843.html http://www.cnblogs.c ...
- Java中timer的schedule()和schedualAtFixedRate()函数的区别
本文主要讨论java.util.Timer的schedule(timerTask,delay,period)和scheduleAtFixedRate(timerTask,delay,period)的区 ...
- SPI、I2C、UART三种串行总线协议的区别和SPI接口介绍(转)
SPI.I2C.UART三种串行总线协议的区别 第一个区别当然是名字: SPI(Serial Peripheral Interface:串行外设接口); I2C(INTER IC BUS) UART( ...
- VS2017 IDE开发工具选型、安装和使用
原文地址:https://blog.csdn.net/boonya/article/details/78739500 距离上次使用VS工具已是2年前了,这次准备选择比较新的版本来开发桌面程序了.总的来 ...
- fork()和写时复制
写时复制技术最初产生于Unix系统,用于实现一种傻瓜式的进程创建:当发出fork( )系统调用时,内核原样复制父进程的整个地址空间并把复制的那一份分配给子进程.这种行为是非常耗时的,因为它需要: · ...
- (面试)写出下面switch语句的输出结果
(1) public static void main(String[] as) { int a = 0; switch (a) { case 1: System.out.println(&q ...
- SNF平台从sql server兼容oracle的处理方式和开发方式
前几天有这样一个需求,就是让SNF平台BS版的基础程序全面支持Oracle数据库. 初一看这是一个很大的工程,因为大家都知道 Sql和Oracle的语法有很多的不一样,如 top .日期获取.类型之间 ...