Working with React and Redux, I use a simple pattern to make my components reusable and to reason about.Over the past 1 and half year working with React, I have realised that anyone who is starting to work with React and Redux always faces a confusion of deciding which component should be interacting with the redux store and which components should just depend on there on own state.
So, in this article I will make an attempt towards making this distinction between when to choose component state and when to choose Redux store easier.
To start with, let’s focus on React first.
React has two types of components:-
- Smart Components
- Dumb Components — Also called as Presentational Components
The way I distinguish between the two of them is:-
If a component needs to hold state then it classifies as a Smart Component.
If a component just needs to display data and can receive that data from it’s parent component than those are classified as presentational components or dumb components.
For Example:- Let’s say we have an e-commerce application where in we have product listing page which displays a list of products.
In this scenario, a skeleton or a bare layout would have the following higher level components:-
The ProductsContainer component here would focus on getting a list of products and then iterate through each of the products and render each Product Component.
In here we can call ProductsContainer as a Smart Component since this component holds the state which in this case are a list of products.
The sample code for Product component which is our Presentational Component would look something like this:-
The above is a Presentational Component, since it’s only responsible for displaying data and it receives that data in the form of props from it’s parent component.
So in conclusion if a component holds state and manipulates it, it’s a smart component and if a component just displays data which it receives in the form of props, then it get’s classified as a presentational component.
A golden quote from Dan Abramov that highlights this is:
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.
That was about Component State, the next question which comes to our mind is which data should go inside the redux store.
The way I classify it is when ever state needs to be shared by multiple components or multiple pages and we need to persist some data over route changes, all that data should go inside the redux store.
To continue with the same example, let’s say all those products have a buy now button and we have a cart which should keep all those items for which the buy now button has been clicked.
This cart information needs to be persisted on a lot of pages and across components like the header component where in we will show the cart count, the checkout page and the payment page.
This is a clear indication that the products added in the cart should go inside the redux store rather than the component state.
This brings us to another distinction between components:-
- Any component which is connected with the redux store is classified as a Container component.It can dispatch actions and update the redux store via the reducers.
- The components which aren’t connected to the redux store go inside the components folder.Now these components can also further be classified as Smart and Dumb because even though they are not connected to the redux store, they still can hold state by calling some API and persisting that data only till the lifetime of that component.
The ShoppingApp component can classify as a container component and be responsible for fetching the initial cart count and login information.
We won’t be going in depth into the functioning of redux and the different redux functions like mapStateToProps, action creators, dispatchers.
All these things can be read from Redux Docs.
Mockup for the final app that we will be building will be something like this:-
After adding reducers, components, containers, actions an example of how my directory structure would like is:-
In here ShoppingApp will be connected to the redux store and would dispatch an action to get the initial cart data.This makes ShoppingApp as the container component.
ShoppingApp would pass this data to header component.
This makes header as just a component and since it is not having it’s own component state, it further gets classified into a presentational component.
ProductsContainer in redux terms does not qualify as a container component since it ain’t connected to the redux store but since it is having it’s own component state which classifies it as a smart component.
The complete code for the above example can be found on the following codesandbox url:-
For some styling I have added react material-ui.
So in conclusion, if your component needs to interact with the redux store, handle data and dispatch actions then it should go inside containers otherwise inside components.