How to use Presentational/Container components in a Redux app
Have you read about Presentational/Container pattern but are still not sure how it looks when it’s used correctly? When should you use it and when should you NOT use it?
Let’s find out!
What is it?
Before we start, let’s take a quick recap of what the pattern is.
The key idea is that you want your components to do one thing. Either present something visual (presentational component) OR fetch data (container component).
- Presentational components are usually stateless, contains DOM markup and optionally callback functions.
- Container components don’t have any DOM elements or styles, but they do Ajax calls, calls Redux Actions, or fetch data from Redux store.
The reason to split it up this way is the separation of concerns. It is easier to test and reuse components.
A much more in depth explanation can be found here
Start without it
You should not think about presentational/container components in the early stages of your application development process. At the start, you should only focus on writing regular React components and get things to work.
If you start planning for a presentational/container architecture before you have written any code, there is a big chance that one of the following will happen:
- You get confused and get stuck
- You will write unnecessarily complicated code because you will write presentation/container components that are not really needed.
When to use the pattern in a Redux app
When your application grows, you will reach a point where you will benefit from introducing the pattern. But when do you know when you have reached that point?
Let’s look at an example.
You can use the container/presentational pattern when using both regular Ajax calls inside your components, or when you are using Redux to fetch data. In this example, we are looking at using Redux to fetch data.
A new Redux app
When you start coding your Redux app, you usually start with a wrapper component that receives the data from the Redux store. Something like this:
const BlogPost = ({}) => (
<div>
<h2>First version of my redux webpage!</h2>
</div>
)
export default connect(mapStateToProps, mapDispatchToProps)(BlogPost)
connect is a Higher Order Component (HOC) that returns a new component. Learn more connect and HOC in my previous articles.
This simple code actually uses the container/presentational pattern. The PlogPost component is the presentational component and the component returned from connect is the container component.
We can visualize it as a component graph like this:
That’s a minimalistic graph. Let’s add some more stuff to it!
Add a feature (and some technical debt)
Now let’s say we implement a header where a user name should be visible. Complete code example here:
Our component graph now looks something like this:
We now have 3 nested components in our Page component. For LoggedinUsername
to be able to access the username, we need to pass it down as props, through both Header
and LoginSection
.
That means that Header
must know about the username when it shouldn’t need to. What if we decide to move LoginSection
to the sidebar instead? Or if we want to delete it completely? It would be easy to forget to delete the username props passed into Header
. Also every time we want to display more data in LoginSection
(email for example) we need to update Header
.
This is technical debt that we can resolve with the container/presentational pattern!
Introducing the container/presentational pattern!
Remember that I told you we already are using the container/presentational pattern with BlogPost
and the connect function?
It is possible to connect Redux to any React component in your application.
So the way to solve our issue is to connect it to the component that needs the specific type of data. In our case, we connect directly to LoginSection
LoginSection
is our presentational component and the component returned from connect
is our container component. Now we no longer need to pass username to Header
.
Running code example here:
Final words
It’s worth noting that this is a simplified example. In a real production application, you will have much deeper hierarchies of components so even more unnecessary props are potentially passed down the component hierarchy.
In our case, we already had presentational components because they only contained DOM elements and components. In a real world application you might need to do more advanced refactorings of the presentational components.
There are more scenarios where the component/presentational pattern could be applied than I have demonstrated in this example.