React has a component-based architecture that encourages you to split your codebase into reusable units of functionality. Not all components are created equal though. Let’s look at the differences between two common types, Presentational and Container (also known as “Stateful”) components.
Is There Any State?
To begin with, it should be stressed that these terms don’t refer to any specific React feature. They describe a style of writing React components which helps to maintain modularity and separate out concerns. The existence of the two component types arises from choices made in your codebase.
There’s only one distinguishing factor: container components have state and presentational components do not. In practice, this means that a container component always makes a call to React’s setState() method. A presentational component will never make use of state.
Looking at Examples
Here’s a simple presentational component:
The component is extremely simple. It renders a single h1 tag which displays text passed into the component via its title prop. Let’s now look at a stateful container component:
The container component’s render method is almost identical to that in the presentational component. The difference is the container component sources its text from inside itself, instead of relying on an outside value passed in as a prop.
Each second, the container component calls setState() to update the time key in its state. This causes React to re-render the component and display the new time. Our container possesses its own state.
Characteristics of Each Type
Several unique characteristics tend to arise within both presentational and container components. Looking at presentational components first, the bulk of their code is likely to exist within the render method. They’ll contain very little logic as their behaviour is defined by the outside world.
Presentational components are blissfully unaware of where their data is coming from. They don’t know when (or whether) it will change. Some examples may not even accept props. Here’s a decorational element which simply renders a specific image file:
Container components are much the opposite of their presentational counterparts. You’ll typically find most of your site’s logic ends up within a container component. The render method may be comparatively short as you’ll be spending many more lines fetching data from external sources, transforming it to suit your needs and then storing it into state.
A container component’s render method could consist of a single line that renders a presentational component. You’ve now got strong separation of concerns, with both components having a distinct role that fully respects the other’s. The container component sources the data; the presentational component puts it on the screen.
Here’s how this looks in practice:
BlogPostComponent is our container component. It loads a post over the network. The data then gets given to the View component for rendering. View doesn’t care where it gets its data from – in the future, we could reuse it to display posts fetched from a third-party API such as Facebook or Twitter.
Container components are so called because they tend to encapsulate entire functional areas of your app. They make your project work and represent the app’s backend systems.
In a real codebase, BlogPostComponent would have even more responsibility. It would need to track whether the post has loaded and handle errors during the network fetch. Consequently, the render method may incorporate some basic logic to alter what gets displayed – either an error message, a progress bar or our presentational View component. Presentational components never have any greater responsibility than rendering a specific section of the UI into the DOM.
Advantages of Separating Presentational and Container Components
Using this pattern helps you to organise your codebase and prevents components from becoming too unwieldy. Although it’s not a hard-and-fast rule, diligent separation of the two types improves maintainability as your project’s component count grows.
Try to look for opportunities to refactor as a container component’s render method grows. It’s likely you could take much of its contents and split it into a new presentational component. This makes it easier to reuse the presentational code in the future. It ends up self-contained and capable of operating independently of any specific data source.
Stateful components are less likely to be reused. Non-trivial behaviours naturally accumulate within them, resulting in dependencies on the outside world. That’s not to say they can’t be reused though – a two-stage confirmation button will contain internal state (to determine whether to display “Reset User’s Password” or “Are You Sure?”) but will also be deployed throughout your codebase.
Perhaps more than anything, intentionally distinguishing between Presentional and Container components keeps you aware of where your application’s state lies. Minimising the number of components with state contributes towards a maintainable codebase and helps to separate concerns.
If you can’t decide whether a component should hold state, keep coding and refactor later – it’s probably too early in your project’s lifecycle to know where the complexity (and hence the state) will congregate.