All Posts

Simple React Design Patterns: Container/View

My component is big and tricky to reason about! How can I make it simpler without losing functionality?

This post is about how I learned a useful pattern in frontend development. It assumes the reader has familiarity with React.js.

Last summer, I watched “Simple React Patterns”, a presentation by Lucas Reis, senior engineer at Zocdoc. I was new to using React in production, and wanted exposure to design patterns that served enterprise developers well.

I was happy to hear that he was not advocating creating abstractions for the sake of academic satisfaction. As is the case with many areas of life, the only constant in the world of software is change, whether with business requirements or the people working on your team. Good designs reduce the cost of change.

When applications are easy to test and extend, there are multiple benefits. Developer productivity is increased because the code is easier to reason about, and certain classes of errors are eliminated. Both of these benefits result in the company saving money, and elevated developer happiness.

Lucas has a blog post which covers all the 3 patterns from his live presentation.

One of those patterns (Container/View) sounded like it could make an immediate impact on the project I was working on, so I did some further reading. I wanted to make sure I understood the idea more thoroughly before making the changes in production code. I’ve added links to those resources at the bottom.

Despite the helpfulness of the readings, I don’t internalize new ideas until I try them out. For this pattern, I split up an existing medium-sized component, a page header that fetched and displayed names and dates from a server.

Since then, most React components I write are made with this pattern in mind.

Questions

These are questions that I had (and answered) over time.

  1. What if I’m not planning to reuse the container or the view? Is the time and cognitive overhead worth it?

This separation significantly improves readability even if the pieces will only be combined once. This will help new developers to understand your code more quickly when they read the codebase for the first time. Not every design pattern is meant to help to make your code more DRY (which was an unspoken misconception that I once had).

  1. I’ve split my original component into container and view, but the container component is still too large.

If there are is business logic or behaviors that can be split up, you can glue together a container out of several other containers which are individually easy to reason about. Your choice of glue might be a higher-order component (HOC), or with function composition (using a function like compose from a library like recompose). Michael Jackson strongly advocates render props over using HOCs. Exploring this question further is a topic for another time.

  1. Why does this pattern work well? Is it related to another good idea?

While this technique may have different names in other languages, I see it as a close cousin of the more well known “MVC” (Model-View-Controller) pattern from classic software architecture books. More generally, separation of concerns makes software easier to reason about (more is written about this under the term “Single Responsibility Principle”). Even though React is described as just the “V” in MVC, the reality with Single Page Applications is that we often entrust React Components with many more responsibilities. Using this pattern helps to use the library as it was originally intended, as a way to transform data (as props) into HTML.

  1. Is it OK to not start with a container and view component right away?

Absolutely. It usually doesn’t take much time to split up a big component into a container and view. The view is just the render portion of the component, so the most lengthy part of the refactoring would probably be threading the appropriate props through in the container, or moving processing from inline javascript in JSX back up to the container. As with any refactoring, it’s a good idea to have a unit test written (even just a Jest Snapshot) before you perform the refactoring so that you can be confident that a regression isn’t introduced.

Further Reading

“A container does data fetching and then renders its corresponding sub-component. That’s it.” — Jason Bonta

Other Names

  • Container/View
  • Presentational/Container
  • Thick/thin
  • Smart/“dumb”

From a diversity and inclusion perspective, I recommend Container/View because it is the shortest phrasing which also has neutral connotations.