The Back End of the Front End – State (Part 1)
What is State?
When working with static, content-based websites, we often do not consider “state,” if at all. It’s only when our applications become more interactive that we need to think of state management approaches.
So, what is “state?” Chris Ferdinandi puts it succinctly in his article, “State-Based Components with Vanilla JS”:
“State is data at a particular moment in time. It’s the present 'state' of your data. Get it?”
Why do we care about managing our application state? As Raquel Moss explains in her article, “What is State? Why Do I Need to Manage It?”:
“For me, the key to understanding state management was when I realized that there is always state. Whether or not I’m managing it, with an interactive web application, there is always state — users perform actions, and things change in response to those actions.”
Managing state is also important for sharing state across your components. Ensuring that your UI components have access to the correct, current state is essential for your application to render correctly.
State Management Overview
Once you decided that your application’s interactivity requires state management, it helps to understand some general concepts of managing state before selecting a tool.
Typically, your state management includes some or all of the following elements, which are consistent regardless of what framework or tool you use:
A store is a location where your application state is — ahem, *stored.* This location is typically an object, sometimes with a level of abstraction the tool provides.
Properties are the individual data points used to track your application’s state. In the above example, isLoggedIn, couponCode, and Cart are examples of properties.
Actions are functions or methods used to update properties in a store. You can think of this as a “setter” method for an object.
Selectors are functions or methods necessary to retrieve a property’s current state. You can think of these like “getter” methods for an object.
A reducer is a state management method where a separate function receives the actions, decides how to handle them, and then creates a new state and returns a copy of it instead of mutating the state directly.
You can think of a reducer like a bookkeeper with a ledger. Every state update is similar to a transaction. Imagine if every time a transaction occurred, the bookkeeper erased the current account balance, updated the balance based on the transaction, and then recorded the new one.
There are two issues here. First, you would have no way to identify duplicate requests or transactions. You would also have no understanding of your account change history or why the balance was updated.
Like a good bookkeeper, a reducer can keep a record of state and updates to ensure state is updated appropriately and aligned with best practices.
Effects are functions or methods that subscribe to or listen for state update events and perform side effects based on those changes.
State Management Tools
A variety of state management options are available depending on what framework you use. Some of these options are built directly into the framework (such as React Hooks), while others are third-party libraries you can integrate into your app. While there are countless other libraries you can use, I’ll go over the most popular here.
“State-Based Components with Vanilla JS,” by Chris Ferdinandi
Many different state management libraries are based on the Redux model. This model comprises three principles:
A single source of truth
State is read-only
Pure functions make changes
In Angular, the NgRX, NGXS, and angular-redux libraries are all based on the Redux pattern and provide different features depending on how complex your application’s state management needs are. The article “Angular State Management with Redux Pattern” provides a comparison of these three options.
If you are interested in state management options without using an external library, check out Seid Mehmedovic’s article “Angular Application State Management: You Do (Not) Need External Data Stores like NgRx, Redux, and Other” for recommendations.
React provides robust tools within the state management framework. If you don’t need a complicated or Redux-based state management tool, you can leverage React features like Hooks, Effects, or Context to keep track of your application state. In “Application State Management with React,” Kent C. Dodds breaks down a solution using the React Context API for state management.
Redux is lightweight and popular when it comes to external libraries, but it does have a learning curve. The article outlines best practices you would be wise to start with to reduce confusion.
XState is also popular and includes a state machine as well as helpful tools like statecharts and visualizations. It has templates available for React, Typescript, Vue, and Svelte.
Vuex is Vue’s official state management library and is also based on the Redux pattern. You can read Michael Thiessen’s article “State Management Without Vuex” for state management options using Vue’s built-in functionality.
Ultimately, the tool you choose will depend on your application’s complexity and how comfortable you are with its syntax and structure. You would be wise to start as simply as possible and only add additional features if necessary. Remember the agile concept of YAGNI — “You aren’t gonna need it” — and build for now, not later.
Hopefully, you now have a better understanding of state management and some best practices for choosing a tool. Keep an eye out for this series’s next installment, focused on APIs and microservices architecture, coming up in October.
Cecelia Martinez is a Women Who Code Track Ambassador and a Success Engineer at Cypress.io.