Redux: When & Why to Use a State Container with Your JavaScript Apps
by Tom Helvick
Modern frontend applications can do a lot. In the early days of the internet, doing something on a website often involved loading a new web page, allowing the server to process your request and return a response. Increasingly, however, JavaScript applications now allow websites to do a lot of work on the client-side. As a result, you can use entire websites without ever having to load a new page. Most of the work is done in your browser without further requests sent to the server.
As such frontend applications become more complex, however, the browser must store and update increasing amounts of data and information about the user session. This data is called the “state” of the application. With modern frameworks like React and Angular, managing the state of an application often involves tracking changes to dozens of components on a web page. To address this monumental task, developers have created state containers and rules for state management in complex applications. Redux is one such tool to manage state and provide a single source of truth for complex applications.
Redux is not a magic bullet, nor is it a must-have for every project. Indeed, like any tool, using Redux includes tradeoffs. It optimizes and makes deterministic the state of complex applications. However, it introduces hurdles and restrictions on how you develop your application. In this article, we’ll examine when Redux is useful and how to start implementing it.
Why Use Redux: What Does It Do?
Understanding Redux requires an understanding of how modern JavaScript frameworks work. Generally, web applications involve dozens of features. In JavaScript frameworks like React or Angular, these features get defined as reusable components. In turn, each of these components has its own local state. It also has any properties passed down from its parent components. Indeed, most applications involve multiple levels of nested components. For state management, it’s best practice to keep stateful information in the highest-level parent components.
Keeping state in the top level parent component is often a satisfactory solution for many applications. Not all apps need Redux. Nevertheless, sometimes keeping state inside a component produces issues, even if that component is the parent of all other components. So, Redux separates the data from the actions on that data, using the principles of functional programming. We store state data as plain objects or arrays. Then, we make updates to that data via pure functions.
State Container = Single Source of Truth
The core of Redux architecture is the container that holds all the application’s state information. This container is conventionally called the “store” in Redux. That store holds the application’s state as a group of plain objects and arrays.
Various components within our app then subscribe to the store to receive updates. When the store changes, Redux pushes state changes throughout the application. As a result, Redux now becomes the single source of truth for our entire application. Any time we need to lookup or share state information, we turn to the Redux store to find the answer. Therefore, the way our application performs becomes deterministic because stateful information can only come from one place.
Editing State Directly vs. Emitting Actions
In a typical application, we might make changes to a component’s state directly. For example, in a React application, the common pattern is to use the “setState()” method to update the state of a parent component. Then, you pass those updates back down to the child components as properties (aka “props”).
On the other hand, in a Redux-driven application, we add a new layer of abstraction to changing state. Specifically, we create “reducer” functions that can make changes to the state without side effects. Then, when we want to change the state, we simply make a call to the proper reducer function. To call the reducer, however, we dispatch a plain object that describes the change we want to make. To see this in action, check out the getting started docs.
What You Can Use Redux For
You could add Redux to any JavaScript application. However, in simple applications, creating a pure function reducer, creating a state store, and then rewriting the app to dispatch objects that describe the changes would be overkill.
Consequently, Redux is most useful for complex applications where it’s clear that state management is going to be difficult. Some things you can do with Redux:
- Persist global application state to local storage and reboot application from that point in the future
- Attach a playback of current state and user actions to bug reports
- Save an undo/redo history without major changes to how the code is written if using Redux architecture
- Decouple the UI from the business logic to allow for alternative interfaces
- Make asynchronous updates to state without deadlocks or bugs from conflicting state in various components
When to Use Redux
The creators of Redux have been very clear. Not every application needs or should use Redux. From the official docs:
In general, use Redux when you have reasonable amounts of data changing over time, you need a single source of truth, and you find that approaches like keeping everything in a top-level React component’s state are no longer sufficient.
And from Dan Abramov, one of Redux’s creators:
It’s not designed to be the shortest or fastest way to write code. It’s intended to help answer the question “When did a certain slice of state change, and where did the data come from?”, with predictable behavior. It does so by asking you to follow specific constraints in your application: store your application’s state as plain data, describe changes as plain objects, and handle those changes with pure functions that apply updates immutably.
Most experts agree that it will be clear when you need Redux. If you’re not sure, you probably don’t need it yet.
Using Redux Effectively
Redux has become very popular, but it is just a tool. When you need to manage complex state in a JavaScript application, it can be very powerful. However, if you implement it before you really need it, it could create more headache than it’s worth. Redux is a tradeoff that opens up complex possibilities, but at a cost to developer flexibility and speed. Use it wisely.
About Intertech
Founded in 1991, Intertech delivers software development consulting and IT training to Fortune 500, Government and Leading Technology institutions. Learn more about us. Whether you are a developer interested in working for a company that invests in its employees or a company looking to partner with a team of technology leaders who provide solutions, mentor staff and add true business value, we’d like to meet you.