After React Baby Steps, it was time to learn Redux. Yes, because it’s popular, but also because I’ve found that my React Redux-free app has one top component propagating props to the leaves of the component tree. So components in between, even if they don’t need some props, have to receive them just to propagate them down. Redux manages state and allows us to access it from any level in the component tree.
After some basic courses, even if straightforward, I had to bang my head one whole day (and night) to be able to refactor a plain React app to a Redux version properly. That’s why this early article on my Redux learning path, to summarize and share my findings. Here you can find my first Redux version of the app.
Note: Redux can be used without React, but I am assuming React-Redux usage.
- Getting Started with Redux – a basic React video course from Dan Abramov – the creator of Redux
- Source Code for the course above for each chapter
- Source Code in the form of a well structured React app (highly recommended)
- Notes (and a partial transcription) of the course
- Redux Official Website
Presentational and Container Components
It’s important to understand this topic. Presentational components already have data and handlers provided via props, so they can only worry how to render data and call provided functions. Container components are opposite – they are not concerned about UI, they provide data and business logic for presentational components.
In Redux we create container components with the
connect function by providing data and behavior which in return gives us higher order components to enhance our component. That way, the enhanced component will automatically have everything without worrying about how to get it. If you check my app here, you can find presentational components in the components folder and container components in the containers folder. There is no strict rule on how to do it. For example, the
App component is a container. It prepares the initial state and provides some data for the presentational component below (
ReactCountries is a presentational component that uses some props to render. The callback doesn’t have any business logic and has both presentational and container components inside. Other container components inside are preparing things relevant to different parts of the application (toolbar, list, add dialog, etc.). That way, we don’t have to propagate everything from the top but rather introduce containers where it makes sense to provide data for the underlying presentational component.
I highly recommend Thinking in React; it will help you understand this topic and structure your React app properly. Don’t worry; it takes some time to get it.
State, Reducers and Actions
One of the first things you will do in a Redux app is to think about state/reducer organization and actions. Each reducer has its own corresponding part of the state object it is responsible for and is not able to access other parts of the state. There is no strict rule here. For example, I have 3 reducers:
countries (managing an array of user’s countries),
allCountries (managing the DB of all countries) and
ui (managing various parts of the UI state like filters, visibility flags, messages, etc.). Check Dissecting Twitter’s Redux Store to get an overview of how smart guys design their store.
For now, I feel that it makes sense to keep logic in reducers and make actions thin.
Preparing State Data in Container Components
In a pure React app when you need to prepare some data (using an API/DB for example) in the state, you can easily do it in the
componentDidMount lifecycle method of the top component (it has access to
this.state). But in a Redux app, the state is not managed by React anymore, and I’ve lost some time to realize how to do it, although it’s straightforward. The problem is that you don’t have access to
dispatch from lifecycle methods, so I didn’t know how to store data in the state when ready. If you take a look at the
App container component, you will see that the solution is to add fetching logic in
mapDispatchToProps, where you have access to
dispatch, then to enhance the current container component using
connect (and not the underlying presentational component) so that it can access
componentDidMount. and then just to render the underlying presentational component, passing down the required props.
Accessing State Data from Reducers
Sometimes you will need to access some state data from a reducer that doesn’t have access to it, as it manages another part of the state. My current solution for this is to pass required state data down as props to the component that will, in the end, invoke a handler and pass the data back to the action creator, which will pack data in an action and thus make it available to any reducer.
I am not sure what the proper terminology is, but I’ve stumbled upon this problem – let’s say I dispatch one action, there is some logic going on in the reducer, and depending on some condition(s), I may want to invoke another/second dispatch. Example: 1) save something to the DB and 2) if successful – show a message. With my current (basic) level of knowledge, I am not aware of how to do it.
- Building React Applications with Idiomatic Redux – this course will pick up where we left off with the Redux fundamentals course.
- React Countries refactor v2 with the new Redux knowledge implemented
- A new blog article 😀
At first, I was sure that Redux is simple because it only has to manage the state. Then, I realized it has many components but seems logical. However, when I tried to apply it, I had more questions than answers and had the impression that it’s too complex and difficult. Finally, I made the transition from pure React to a Redux app, and it looks OK. A little bit more complex, with more files and code, and more time consuming, but it is giving me hope and motivation to continue with more advanced topics and witness the real power of it.