Yes, I love the Simpsons

A common pattern among React applications is the Presentational / Containers components structure that avoids mixing tiny UI elements with complex logic like AJAX requests or data processing.

If you are not familiar to this pattern, I highly suggest you to read the Presentational and Containers components article before you continue this one.

But as stated in the Containers characteristics listed by Dan Abramov (in 2015):

[Containers components ] 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.

My goal is to question this sentence in the light of the patterns that have emerged since then and to propose you a viable alternative.

Container components over time

At the beginning of it’s life in the codebase, a Container component often follows the rules. It performs an AJAX request, makes some data processing and updates its own state. This state is then consumed by the JSX (presentational + containers) in the render method.

In my humble experience, over time the Containers can slightly begin to be responsible of some UI logic like maintaining an open / close state for a modal, handle a callback on user interactions and so on.

As the code-base grows, data processing logic can get too tied to the view logic which harms the initial goal of separation of concerns.

Controller components to the rescue

To solve this problem, I started to think that there were not only two, but three kinds of components:

Controller components (render props), that are responsible of data gathering and processing. From my perspective, they must not contain any JSX but a wrapper to ensure they don’t handle any view logic.

(render props), that are responsible of data gathering and processing. From my perspective, they must not contain any JSX but a wrapper to ensure they don’t handle any view logic. Container / stateful view components, that makes the glue between dumb and controller components to create a more complex view unit. Complex UI interactions should be handled in there as well.

components, that makes the glue between dumb and controller components to create a more complex view unit. Complex UI interactions should be handled in there as well. Presentational / stateless components: UI units without lifecycles that only takes props and make a direct use of them

A clear advantage with this structure is separation of concerns: individuals can focus on the view layer while others can work on the logical layer.

Keep in mind that as any kind of components, Controllers are composable. For instance, it means that you could distinguish AJAX controllers from data processing controllers.

Coding workflow proposal

While we are at it, I may suggest you a way to develop a feature from end to end having this layer separation in mind:

Create the container component and define what data you will need.

Create the missing controller components and render mock data from it to match the specs you’ve defined in the container components.

Use the mocked controller components in combination with your unitary presentational components and see the result.

From this point, the “contract” between the view and the logic units is defined, which makes it easy to split the work between teams.

Quick sample: TodoList

I made a tiny repo for you to explore and play with the code below: todos-controller-sample

The Container glues the TodosController with the Presentational TodoItem component, and has a state to manage the input changes.

TodosContainer.js

TodosController holds the todos data state and passes to the Container the callbacks needed to create and delete a todoItem. In a real case scenario, the Controller would be triggering an AJAX call to fetch the todos from a server and do CRUD operations.

If you use redux in combination with React, the Controller would probably be connected to the store in order to dispatch actions and read the redux state, then pass the data to the Container.

TodosController.jsx

TodoItem.jsx

I hope this point of view has enrich your thoughts in any way, if you have suggestions or remarks I will gladly answer them !