In his Reactathon talk about The State of Redux in 2019, Mark Erikson, the Redux Maintainer, said: “Redux is used in 55% of React apps and is going to be around for a long time”. And he was right. Redux is still popular for helping developers build consistent user interfaces and cope with complex logic for app state management.
However, there are many talks about overusing Redux. It appears that far not all React apps really need Redux. In many cases, the app state and data can be managed using alternative approaches with lower overhead and simpler implementation.
Let’s look at what Redux is, what problems it solves, and consider whether using Redux in your app is reasonable and beneficial.
React app state management
The main advantage of React web apps over static websites is their interactivity. The React app interface responds to user actions with changes in the interface. Sometimes those changes take place right in the UI component the user interacts with. But sometimes they affect multiple components and get reflected in different parts of the app.
With hundreds of actions a user can take in the interface, you need a good system and logic in place to manage the dynamic state of your app. This process requires passing data to multiple app components, syncing between them, and storing the app state.
This is when Redux comes in handy. It controls when a certain slice of the app state changes, where a particular piece of data comes from, and whether your app responds to it with predictable behavior or not. So what is Redux and how does it work?
Redux state management library
Without Redux, each component of a React app handles user input and manages its own state. Sometimes it shares the input in the form of props with other components that rely on the changed data. If the process involves only components having parent-child relationships with the component initiating a state change, the logic is simple.
However, if a state needs to be shared with a lot of components that belong to different parts of the app structure, the data flow gets more complex. In such cases, the so-called props drilling problem appears. Props drilling is a bad practice of passing properties through components down the hierarchy without having them used in the process. With time it results in an enlarged codebase where it’s difficult to keep track of those props.
If you have a small app you can continue using the default React approach to state management. But in large apps, it’s too hard to handle data flow this way. Adding Redux to the app allows keeping the global app state in a single store.
With Redux, each component pushes its data to the global store and influences the app state as well as listens to the changes initiated by other components. The difference that Redux makes to data flows in the app is illustrated in the diagram below.
If you want to add Redux to your React app, you’ll need to use the official React Redux binding library provided and maintained by the Redux team.
React Redux UI binding library
React Redux is a library that handles the interaction logic between your app components and the global store in Redux. It saves React developers from reinventing the wheel and writing repetitive code.
You can rest assured that React Redux is always up-to-date, adheres to the design best practices of React, and creates a helpful abstraction layer between components of your app and the Redux store.
Moreover, this library automatically does some store performance optimization. For example, it ensures that your app components rerender in response to the state change only when it’s needed.
Cases when to use Redux
Imagine you build a dashboard for data visualization. The dashboard includes a set of widgets and provides users a lot of options to customize them. A user will adjust widgets according to their needs and the app state will change based on the user input.
If you don’t use Redux, the responsibility of managing and sharing the state gets distributed between all widgets. In this case, you might have a tough time fixing data inconsistency bugs. But if you add Redux, all widgets start to communicate via a single global store, which simplifies keeping the state of all widgets in sync. And here are several more reasons why use Redux in your app:
- You need the same state to be shared between multiple components reflected in different parts of the app.
- The app states change frequently and different components can initiate changes simultaneously.
- The app has a medium-to-large codebase with several React developers working on it.
- You need to monitor and record how the app state is changing over time to have a clear understanding of your app behavior.
- You need convenient tools to fix state management bugs quickly and want to leverage Redux DevTools for testing.
This example illustrates the main use case for Redux—complex logic for managing state shared between a lot of components that belong to different hierarchy trees in the app structure.
Cases when not to use Redux
Even though Redux is a great tool for state management, it's important not to overuse it. Using Redux in simple and small apps may add unjustified complexity to the app architecture, lead to wasteful memory usage, and require adding a caching solution to backup the application state. You might not need Redux if your app state management:
- Implies simple UI changes that follow plain logic.
- Handles data that comes from a single source per view and there is no or little risk of having data inconsistency bugs.
- Requires pushing data as props to components within one subtree in your app structure, which can be done using the React Context dependency injection.
For example, consider modals open/close state. It's important to render modals at the root, but keeping their states in Redux isn’t necessary. A better approach, in this case, would be to create a Portal for the modals and handle their state only where they are being toggled.
Redux is a great tool for building large-scale applications requiring global state management. For simpler cases, there are more lightweight tools, like MobX, PushState, or React Context.
From the engineers’ point of view, a huge benefit of Redux is in improving the developer experience. It makes handling complex logic easier by keeping it organized rather than dispersed throughout the app. On top of that, it provides convenient testing and debugging tools that save software engineers a lot of time.