Top 6 React state management libraries for 2022
Tags: react, redux, javascript, webdev
Published: 2022-01-21 08:46:38

_by author [Arek Nawo](https://blog.openreplay.com/authors/arek-nawo)_


State management is one of the most important aspects of every app. The app’s state dictates what users see, how the app looks, what data is stored, and so on. Thus it’s no wonder that there are so many open-source libraries designed specifically to make state management easier and more enjoyable.

From the multitude of JavaScript UI frameworks, React is likely the one that enjoys the most vibrant ecosystem, including state management libraries. This article will go through the top 6 of those libraries and compare them to see which one is the best choice for your next React app.

## Recoil
![Recoil landing page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/puh3yi632xy4rgvk4vj3.png)


Since its announcement in early 2020, [Recoil](https://recoiljs.org/) has gathered a fair bit of interest from the React community. Partially thanks to its **atomic**, React-inspired approach to state management, but also thanks to it coming straight from the Facebook team. Although it’s still in an “experimental” phase, Recoil is already relatively stable and feature-rich.

The core concepts to understand in Recoil are **atoms** and **selectors**. An atom is a unit of state that wraps and represents a single state property. You can think of it as an equivalent to React’s local state (`useState`), but with the ability to be shared among components and created outside of them.


```javascript
const isAvailableState = atom({
  key: "isAvailableState", // unique, required key
  default: true, // default value
});
```


On the other hand, selectors are pure functions that depend upon atoms or other selectors to calculate their value, recomputing when any of its dependencies are changed. They can be readable, writable, and even async, integrating nicely with React Suspense.


```javascript
const statusState = selector({
  key: "statusState", // unique, required key
  get: ({ get }) => {
    const isAvailable = get(isAvailableState); // access value of the atom

    return isAvailable ? "Available" : "Unavailable";
  },
});
```


To use atoms and selectors, you’ll need to utilize one of Recoil’s hooks, like `useRecoilValue` or `useRecoilState`.


```javascript
// Inside React component

// state's value and state setter
const [isAvailable, setIsAvailable] = useRecoilState(isAvailableState);
// state's value only
const status = useRecoilValue(statusState);
```


Recoil builds upon atoms and selectors to provide advanced tools in every state management area - from coding to dev tools and testing. This approach makes Recoil easy for beginners and powerful enough for advanced users.

## Jotai
![Jotai landing page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fwpdp65swek3wf89sm36.png)


Staying in the realm of atomic state management, [Jotai](https://jotai.org/) is another library worth considering. It’s similar to Recoil, but with a smaller bundle size ([3.2 kB](https://bundlephobia.com/package/jotai) vs. [21.1 kB](https://bundlephobia.com/package/recoil)), more minimalistic API, better TypeScript support, broader documentation, and no experimental label!

Apart from all the above, the most significant difference between Recoil and Jotai is probably the performance, specifically the **garbage collection**. If you noticed from the previous snippets, Recoil tracks its state by string keys - that’s why their required and must be unique. It’s uncomfortable, ineffective, and can lead to memory leaks.

In contrast, Jotai doesn’t require keys and depends entirely upon JavaScript’s built-in `WeakMap` to track its atoms. This means the JS engine handles garbage collection automatically, allowing for optimized memory usage and thus better performance.

Jotai simplifies its core concepts even further, meaning that here, pretty much everything is an atom! Here’s how the previous Recoil snippets translate to Jotai:


```javascript
const isAvailableState = atom(true);
const statusState = atom(({ get }) => {
  const isAvailable = get(isAvailableState); // access value of the atom

  return isAvailable ? "Available" : "Unavailable";
});
// Inside React component

// state's value and state setter
const [isAvailable, setIsAvailable] = useAtom(isAvailableState);
// ignoring state setter
const [status] = useAtom(statusState);
```


Jotai includes pretty much all the features you’d find in Recoil, with similarly simple integration with React Suspense and even other tools from React ecosystem like Redux or Zustand.

## Redux
![Redux landing page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/liswyos5gp69na5rc7pd.png)


Speaking of which, no React state management library list would be complete without [Redux](https://redux.js.org/). Although Redux has received a lot of criticism recently, it’s still a great, battle-proven library that can go hand-to-hand with modern solutions.

In Redux, you can change the state only by dispatching an **action** - an object describing what should happen. This, in turn, runs a function called a **reducer**, which, given an action object and previous state, returns a new state.

While the Redux model has been around for a while now, its biggest issue is the related **boilerplate**. Writing actions to describe every possible state change and then multiple reducers to handle those actions can lead to a lot of code, which can quickly become hard to maintain. That’s why Redux Toolkit was created.

Nowadays, [Redux Toolkit](https://redux-toolkit.js.org/) is the go-to way to use Redux. It simplifies the store setup, reduces the required boilerplate, and follows the best practices by default. Additionally, it comes batteries-included with, e.g., [Immer](https://immerjs.github.io/immer/) to allow for easy state changes, and [Redux-Thunk](https://github.com/reduxjs/redux-thunk) to work with async logic.


```javascript
const exampleSlice = createSlice({
  name: "example",
  initialState: {
    isAvailable: true,
  },
  reducers: {
    makeAvailable: (state) => {
      state.isAvailable = true;
    },
    makeUnavailable(state) {
      state.isAvailable = false;
    },
  },
});
const { makeAvailable, makeUnavailable } = exampleSlice.actions;
const exampleReducer = exampleSlice.reducer;
const store = configureStore({
  reducer: { example: exampleReducer },
});

// Inside React components with React-Redux hooks
const isAvailable = useSelector((state) => state.example.isAvailable);
const dispatch = useDispatch();

dispatch(makeAvailable());
dispatch(makeUnavailable());
```

## Rematch
![Rematch landing page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ofya1bldsl165f5lprqw.png)


Staying in the Redux world a little longer, there’s an alternative to Redux Toolkit that’s worth mentioning. It’s called [Rematch](https://rematchjs.org/) and is lighter, faster, and easier to use than Redux Toolkit.

Rematch builds upon Redux core, simplifying the setup process, reducing boilerplate, and introducing simple side-effects handling with `async`/`await`. All that and more (like a plugin system or great TypeScript support) fits into just [1.7 kB](https://bundlephobia.com/package/@rematch/core) (vs. [11.1 kB](https://bundlephobia.com/package/@reduxjs/toolkit) of Redux Toolkit).

At the heart of Rematch are **models**, which wrap state, reducers, and effects into a single entity. They enforce Redux’s best practices and make state management easier.


```javascript
const countModel = {
  state: 0,
  reducers: {
    increment(state, payload) {
      return state + payload;
    },
  },
  effects: (dispatch) => ({
    async incrementAsync(payload) {
      await new Promise((resolve) => setTimeout(resolve, 1000));
      dispatch.count.increment(payload);
    },
  }),
};
```


The model can then be used to create a Redux store with additional Rematch functionality like **shortcut action dispatchers**.


```javascript
const store = init({
  models: {
    count: countModel,
  },
});
const { dispatch } = store;
dispatch({ type: "count/increment", payload: 1 });
dispatch.count.increment(1); // Action shortcut
dispatch({ type: "count/incrementAsync", payload: 1 });
dispatch.count.incrementAsync(1); // Async action shortcut
```


For more details on Rematch, check out [this article](https://blog.openreplay.com/rematch-a-better-redux).

## Zustand
![Zustand demo page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pm8r9q8q534qw92mjnvk.png)


Weighting under [1 kB](https://bundlephobia.com/package/zustand), [Zustand](https://docs.pmnd.rs/zustand) is the smallest state management library on this list. With that said, don’t let the small size mislead you - Zustand’s simple, minimalistic API can achieve a lot if used properly.

Although concepts like actions or selectors exist in Zustand, the leading role is played by **hooks**. For example, the `create` function used to create a Zustand store returns a hook for use in React components.


```javascript
const useStore = create((set, get) => ({
  isAvailable: true,
  status: () =>
    get((state) => (get().isAvailable ? "Available" : "Unavailable")),
  makeAvailable: () => set((state) => ({ ...state, isAvailable: true })),
  makeUnavailable: () => set((state) => ({ ...state, isAvailable: false })),
}));

// Inside React component
const { isAvailable, makeAvailable, makeUnavailable } = useStore(); // Access whole store
const status = useStore((state) => state.status); // Access selected property
```


On top of ease-of-use and small size, Zustand also addresses common problems in React state management, like usage in React concurrent mode or transient state updates (without causing re-renders).

## Open Source Session Replay
Debugging a web application in production may be challenging and time-consuming. [OpenReplay](https://github.com/openreplay/openreplay) is an Open-source alternative to FullStory, LogRocket and Hotjar. It allows you to monitor and replay everything your users do and shows how your app behaves for every issue.
It’s like having your browser’s inspector open while looking over your user’s shoulder.
OpenReplay is the only open-source alternative currently available.

![OpenReplay](https://raw.githubusercontent.com/openreplay/openreplay/main/static/replayer.png)

Happy debugging, for modern frontend teams - [Start monitoring your web app for free](https://github.com/openreplay/openreplay).


## Hookstate
![Hookstate landing page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/409um0qrgx92phwlefz2.png)


Speaking of hook-centric libraries, [Hookstate](https://hookstate.js.org/) definitely counts as one. This library is focused on providing an excellent development experience using hooks and functional components.

The key feature of Hookstate is, without a doubt, its API and ease of use. Whether you’re working with a global or local state - you can use the same methods with the same syntax. This means Hookstate is not only a global state management library but also `useState` on steroids.


```javascript
const state = createState({
  isAvailable: true,
});
// Wrapped "actions"
const makeAvailable = () => state.isAvailable.set(true); // Changing state outside component
const makeUnavailable = () => state.isAvailable.set(false);
const status = () => (state.isAvailable.get() ? "Available" : "Unavailable"); // Accessing state outside component

// Inside React component
const state = useState();
const isAvailable = state.isAvailable.get(); // Access selected property
```


On top of that, Hookstate is very scalable thanks to its handling of nested state. With this library, you can use nested data structures with little to no performance loss thanks to mutations, scoped states, and other optimizations.

Add to all that a good extension system, TypeScript and Redux DevTools support, and Hookstate looks to be one of the most attractive solutions for fans of React hooks.

## React Context

Although using a dedicated library - especially the latest and greatest one - is tempting, it’s worth noting that it’s not always necessary. In small to medium apps, adding an additional dependency, meaning additional bundle size, complexity, concepts, and more, can create more harm than good.

For such cases, React has built-in tools - namely [State](https://reactjs.org/docs/state-and-lifecycle.html) and [Context](https://reactjs.org/docs/context.html) APIs. Those can do just fine for a vast majority of apps.

The best choice is to stay with the basics until you need something more powerful. Then, explore the options - from the lightweight ones like Zustand to those with the most features and best suit for the job like Redux or Recoil.

## Bottom line

So there you have it - React state management libraries you should consider for this year. Naturally, there are many more libraries like these out there, with more coming out seemingly every day. That’s why this list is likely to change within a year or even sooner. The best choice is to use what works but be aware of what’s out there, just in case something better comes around.