React is a go-to tool for front-end development, loved for its flexibility and performance. However, how you leverage React can vary based on the size and scope of your application. Whether you're working on a personal project, a small business site, or a large enterprise app, each comes with its own set of challenges, particularly around managing state effectively.
In this article, we dive into one of the key hurdles for scaling React applications: state management. Proper state management is essential to keeping your React apps maintainable and scalable as they grow.
Luckily, there are many libraries that can simplify this process. From lightweight options to robust frameworks supported by Meta, these tools can help you manage state efficiently, no matter the complexity of your app.
Our guide will walk you through the most useful React state management solutions and how to apply them, so your apps can thrive and scale with ease.
React Js: An Introduction
The reason React.js and its sister platform, React Native, are growing so rapidly in popularity is primarily because of the productivity and efficiency they unlock in teams. Both platforms are capable of creating highly attractive applications with a strong user experience and unique user interface for tech-based organisations.
Meta leans on its React platform for the vast majority of its own in-house applications and platforms. So too does Netflix, Uber, Airbnb, and Atlassian. Each of these organisations deals with apps and users at a scale that few firms have to regularly contend with.
For developers, React JS excels as a primary option in two ways:
- It’s declarative. React makes it comparatively rapid and ‘painless’ to develop exceptional user interfaces
- It’s component-based. Developers can build, swap, and maintain encapsulated components responsible for managing their own state internally.
The result of these two facets of React is a shift in thinking from developing and managing UI elements to an approach involving the management of React components instead. The role of the developer, in this scenario, is one of composing applications of encapsulated components to make a fully-fledged interface that maximises rendering performance.
The trade-off for React’s great advantages are the significant challenges involved in managing the state of disparate components as apps scale in size and complexity.
What Is React State Management?
When we discuss state in React, what we’re talking about in simple terms is the part of the component that can be altered by a user’s actions. A button press, form action, or cart change may change the state of an app in many possible ways, for example.
A simple, single-page app may only deal with a handful of components and states. Dealing with the challenges of state while apps are relatively small apps is trivial. These difficulties, however, scale at a non-linear rate as applications grow in size.
These challenges begin at an early phase of development but don’t really stand in the way of productivity until future maintenance, updates, and additions are brought into the mix. Attempting to modify an app with dozens of stateful components without a good management solution rapidly runs into a nightmare of unintended consequences and cascading problems.
It’s not uncommon for poorly managed apps to eventually be declared unmaintainable. Immune to updates or upgrades, organisations can be boxed into starting from scratch just to create minor improvements or continue use within a shifting platform.
Using some of the tools available to simplify React state management across components can eliminate mess and complexity at any scale. Creating a solution that can be built on, added to, and updated in the future can keep enterprise-scale apps working for a long, long time to come.
React State Management Libraries
Redux
A state management library that’s been around almost as long as React itself, Redux enjoys status as an official state management solution for React. As a result, it’s been the go-to option for developers of enterprise-scale React apps for some time now.
A defining goal behind the project is to provide a clear divide between a component’s state and its actions.
To achieve this, Redux maintains a global store of states. These states are updated via actions dispatched by an event handler when user interaction takes place.
The store’s updates are communicated to components via subscriptions. Redux’s reducer uses the app’s current state and action to render a new state that is distributed to subscribed components.
The advantage of allowing you to manage component states in a single, global location is in allowing apps to be more easily debugged, more traceable, and more visible for developers. Engineers coming to the project in an advanced state will find it much easier to get up to speed and get started on productive improvements to the project.
Advantages of Redux
- Simplicity. Redux offers one of the simplest possible solutions to state management for apps
- Highly testable. The simplicity and ease of use of the library makes it trivial to apply unit and integration testing
- Highly reusable. Relatively trivial to plug new components into a shared datastore
- Rich ecosystem. Due to its age and popularity, Redux offers a large number of additional libraries, tools, and add-ons to aid development
- Strong Community. Another advantage of longevity, Redux has a large user community available to tackle issues and answer questions
Drawbacks of Redux
- Scalability. The disadvantage of maintaining a single global state makes Redux less scalable than some of our other solutions
- Requires a significant amount of boilerplate code to add to projects
- There are more modern tools available for newer React applications
- Adds an additional layer of complexity
React Hooks
Technically speaking, Hooks aren’t an additional library of their own. Hooks are a built-in state management feature added to React back in 2018. They are, however, used in applications to manage state and in many cases can serve the role independent of any additional libraries or tools.
When first introduced to version 16.8, Hooks solved many problems that developers had been suffering with since React’s initial creation. Their addition to the platform meant that function components could create and manage their own state in the same way as classes. Developers could “hook into” state and lifecycle features from functions for the first time.
Hooks make it practically feasible to share state to and from any component. Built-in hooks provide a way to add state to function components to help solve a wide range of state management problems.
When combined with the Context API, another feature later added to React, developers have the tools necessary to make data accessible across a scope defined to meet the requirements of the app. Easily sharing data amongst components, Context API frees developers from the code and coupling that property drilling requires in a more ‘conventional’ React app.
Hooks and Enterprise-scale Apps
Hooks in combination with Context API are a great solution for a broad array of React apps. When it comes to apps at an enterprise scale, however, it may not be enough to overcome some of the more fundamental challenges that appear at very large scales.
Using Hooks in combination with Redux, however, is a solution ideally suited to large and complex React apps. The combination of the two technologies are particularly powerful where:
- State management is beginning to become unwieldy at scale
- Application state needs frequent updates
- The logic required to issue updates is complex
- Many developers working across a large codebase
- Persistence, serialisation, and side-effects need careful management
Recoil
One of the more modern tools to come to the React ecosystem. Recoil, like Redux, comes directly from meta engineers working in other areas of mainstream React.
The philosophy behind Recoil is in adding functionality such as shared state and derived data in a way in keeping with the original, minimalist, design of the platform.
Officially, the Recoil library is still in the experimental phase of development. Not yet reaching a version one release, this would ordinarily make the library one to skip over for enterprise use. Unofficially, however, Recoil is already being widely used in-house on Meta’s own applications. Combined with Meta’s implicit backing, the capabilities of the library make it difficult for teams to skip over entirely.
Recoil is designed around the creation of a data-flow graph that allows state to be shared amongst React components. The library uses the label ‘atom’ for states and ‘selectors’ for pure functions that can modify them.
Atoms can be updated and subscribed to by components who need to be notified when a state changes, or needs to make changes to the state themselves. Selectors work in parallel with Atoms, accepting either other selectors or atoms as input and creating derived data for components to work with.
This model of shared state is highly effective for apps, only notifying affected subscribers when atoms or selectors are changed. Where the library really shines, however, is being able to swap components seamlessly using an interface shared by both atoms and selectors.
Advantages of Recoil
- Exceptionally easy to use. Built with simplicity in mind
- Reduced boilerplate code. Developers only have to add and maintain selectors and hooks to existing code
- Highly performant. Only updates the necessary parts of the component tree
- Scalable. Splitting state out into independent components makes it a highly scalable solution
Drawbacks of Recoil
- No ecosystem of compatible libraries or tools available yet
- Very little community to speak of so far
- Slow update schedule hints this project isn’t a priority
- Untested platform in real-world development
- Hasn’t hit version 1 yet
MobX
In stark contrast to Recoil, MobX is another library that’s been around for almost as long as React itself. Like Redux, MobX is highly popular and productive, but handles React state management in a very unique way.
MobX tackles state management with an adherence to object-oriented programming principles. By leaning on observables, components subscribing to properties and methods can be updated via a subscription method similar to Recoil.
In contrast to Redux, which relies on immutable data structures to function, MobX relies on direct mutability to ensure references to state objects don’t change over time. The advantage of this approach is in allowing the application state to be updated silently in cases where avoiding side effects is a high priority.
Advantages of Mobx
- Simplicity. Maintaining a single point of entry to manage state means there’s only one place to make modifications
- Highly performant. Built from independent stores, MobX enables you to subscribe only to the resources you need
- Easily testable. An observable store is built using plain JavaScript and can be tested along with any other classes
- Scalable. Stores can be split logically to create an inherently scalable solution
- Rich ecosystem and community
Drawbacks of Mobx
- Less maintainable than other options. Without knowledge of RxJS, poorly qualified teams will have a lot of trouble
- Can be more difficult to track updates through an application
- Documentation lacking in comparison to React-supported options
React State Management for Enterprise Apps
Building React apps at a hobby or even small business scale is a very different challenge than creating an enterprise-level application. Almost every problem of development becomes more challenging as they scale — none more so than state management.
How then, do these libraries and tools match up when it comes to building enterprise-scale applications?
Recoil provides an exciting new way to handle React state management for apps and holds a lot of promise for the future. Currently, it’s still comparatively unproven and doesn’t come with much of the necessary ecosystem or community support. For large-scale enterprise apps, in particular, this is very likely to prove a deal-breaker for consideration today.
Redux, in comparison, is highly proven, well-supported, and widely understood amongst developers. More recent additions to Redux and React have proven to make the library even more capable still. The library still maintains the crown as a default option amongst the highly competitive landscape of enterprise-scale React apps.
Similarly, MobX offers a strong solution with robust reliability. Coming from outside of the Meta-supported family of libraries, MobX offers a unique OOP method of handling state and the advantages and drawbacks that come with it.
Weighing up the pros and cons of each solution, Redux, Recoil, and MobX are each more than capable of providing support for enterprise apps depending on what matters most to your team and how they build within your organisation.