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 SkinnySmart and Dumb, Stateful and PureScreens 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

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的更多相关文章

  1. [Redux] Extracting Container Components (FilterLink)

    Learn how to avoid the boilerplate of passing the props down the intermediate components by introduc ...

  2. (翻译)React Container Components

    原文:Container Components Container Components 在 React 模式上对我的代码有最深远影响的一个模式叫 container component 模式. 在 ...

  3. (翻译) Container Components

    react.js javascript   这篇文章翻译自Medium的一篇文章:Container Components 选择这篇文章翻译的原因是,在刚接触React的时候,这篇文章很好的指引我了解 ...

  4. [Redux] Extracting Container Components -- Complete

    Clean TodoApp Component, it doesn't need to receive any props from the top level component: const To ...

  5. [Redux] Redux: Extracting Container Components -- AddTodo

    Code to be refactored: const AddTodo = ({ onAddClick }) => { let input; return ( <div> < ...

  6. [Redux] Extracting Container Components -- VisibleTodoList

    Code to be refacted: const TodoList = ({ todos, onTodoClick }) => ( <ul> {todos.map(todo =& ...

  7. 【原创】Redux 卍解

    Redux 卍解 Redux - Flux设计模式的又一种实现形式. 说起Flux,笔者之前,曾写过一篇<ReFlux细说>的文章,重点对比讲述了Flux的另外两种实现形式:『Facebo ...

  8. React + Redux 入坑指南

    Redux 原理 1. 单一数据源 all states ==>Store 随着组件的复杂度上升(包括交互逻辑和业务逻辑),数据来源逐渐混乱,导致组件内部数据调用十分复杂,会产生数据冗余或者混用 ...

  9. [react] 细数 React 的原罪

    Props & onChange 的原罪 .「props & onChange 接口规范」它不是一个典型的「程序接口规范」. 当你拿到一个可视组件的 ref,却没有类似 setProp ...

随机推荐

  1. Window修改cmd编码

    Window默认编码是gbk,对一些字符不支持.需在不同语言上切换,急需要调整字符集编码..chcp 功能: 显示或设置活动代码页编号 chcp [nnn]  #nnn 指定的代码页编号 chcp   ...

  2. phpBB3.1和3.2

    闲逛看到一个帖子, phpBB3的论坛经常被机器人注册攻击, 要找人做拦截. 出于兴趣, 联系了一下. 论坛是一个做健康养老调查的社会机构的, 版本3.1, 十年前我还在更新phpbb中文包的时候, ...

  3. spdk 编译动态库( spdk compiles shared library )

    1,dpdk编译共享库 默认情况下都编译出静态库,如果想编译出动态库,把config/common_base文件中的CONFIG_RTE_BUILD_SHARED_LIB改成y即可. 2,spdk编译 ...

  4. 10行代码解析krc歌词文件

    互联网上,我们常见的歌词格式有 LRC.TRC(天天动听歌词).KRC(KuGou ResourCe,酷狗资源文件)和 QRC(QQ音乐歌词):在影视制作中,人们通常会用其他的卡拉 OK 字幕格式,例 ...

  5. 【C++】不要依赖编译器的默认初始值

    最好在定义的时候就给出初始值. 类和结构体给出构造函数. 比如int,在vs的debug和release模式下,初始化的值是不同的.

  6. 查看/修改Linux时区和时间

    一.时区 1. 查看当前时区 date -R 2. 修改设置时区 方法(1) tzselect 方法(2) 仅限于RedHat Linux 和 CentOS timeconfig 方法(3) 适用于D ...

  7. java 记录一下socket的server与client

    package com.test.server; import java.io.IOException; import java.net.ServerSocket; import org.apache ...

  8. 树莓派进阶之路 (019) - 树莓派通过filezilla,samba与PC文件共享(转)

    虽然我们可以很方便的通过ssh譬如putty或者vnc连接操控树莓派,但是毕竟树莓派资源没那么高,在上面编程,调试要吃力的多.所以还是想在pc上编程上传到树莓派或者最好,文件共享,可以直接读写共同的文 ...

  9. 进阶之路(中级篇) - 017 有关于Arduino 驱动舵机及相关问题

    /********************************* 代码功能:通过串口控制电机 使用函数: Serial.available(); //判断串口是否接收到数据 Serial.prin ...

  10. magento登陆

    magento判断用户登录 Magento 登陆之后返回登录之前的页面 magento 在登陆后一般会自动跳转到 My Account 页面 但是经常会有需求 就是登陆自动跳转到 之前的页面里面 工具 ...