Until recently, I was able to get away with React Context for managing shared state between components. It's an ideal solution for most small to medium projects that have only a few bits of state shared across some React components.

However, this quickly gets out of hand as the amount of data your app passes around increases. It's no longer efficient to pass state through common ancestors, nor is it feasible to encapsulate more than a few variables into a Context provider.

It's even more confusing if the state is updated from multiple components in the app, or, to further complicate things, try syncing this data between a server and a client or several clients.

If you've reached this point, I'm assuming you're looking to implement a centralized state management system. So let me get straight to what I learned from:

  1. Implementing Redux in 2022 with Redux toolkit
  2. Experimenting with the relatively new Recoil state management library from Facebook Opensource

Why do you need better state management?

  • Make state changes predictable and transparent
  • Let components talk directly to the store to get/set data; aka decouple component tree from state for better UI performance
  • Benefit from an ecosystem of debugging tools and resources to extend features
  • Above all, make your code more manageable; making it less error-prone and easier to collaborate on

This post is primarily about the state of Redux in 2022; however, I'll also discuss the newer Recoil JS library, which takes a more React-like approach to state management. Personally, I was drawn towards Recoil because it provides a bunch of useful primitives and allows you to compose them to suit your specific use case. Given I'm already a fan of the "React way" of things, I had to implement Recoil to find out if it works as well as it claims. (Spoiler: it does!)


The Redux Ecosystem in 2022

The core ecosystem has come a long way. Redux Toolkit now provides a few packages with many good defaults for setting up Redux quickly.

However, much of the broader ecosystem of libraries is in various stages of development and struggles to keep up with the latest versions of Redux. I couldn't find many libraries that were directly compatible with the newer Redux Toolkit. In most cases, you're left to figure this out on your own, as much of the documentation is also lacking.

Redux is still the wild-west of state management tools, meaning it's very powerful, but be prepared to figure many things out on your own.

What does redux feel like in 2022?

The Redux pattern has remained more-or-less the same over the years. You write logic that describes what's changing, Redux performs the logic on the store and notifies subscribers of state changes as they happen.

The one-way flow of data, action streams, and subscribers are mostly what I think of when someone says Redux, and that's all still the same (from 2-3 years ago). All of this is covered in good detail within the documentation.

Redux Toolkit now provides better ways to get started quickly, such as the createSlice API that generates action creators and action types based on the reducers and state defined. It's also quite useful that createSlice uses Immer under the hood, so you can write mutating updates (e.g., state.name = newName) without having to make copies of objects.

I should note though, I ran into more than a few instances where the use of Immer clashed with other Redux addons.

The tldr is that Redux in 2022 feels straight-forward, but expect to figure a lot of things out on your own the more bespoke usecases.

What is Recoil?

Recoil is another state management system for React by Facebook Open Source. It follows a React-like pattern, and the implementation feels familiar to how we work with React hooks today. While we know that Facebook uses Recoil in several of their internal tools, the library is still relatively new; v0.5 was the latest at the time of writing. This doesn't mean it's unusable, as a majority of the API is stable, and I was able to implement a working store a bit faster than adding Redux to a code-base.

The neat thing is that it supports all the latest React features (like concurrent mode) out of the box.

Does Recoil replace Redux?

It doesn't. While you can technically recreate the 'redux pattern' using the primitives provided by Recoil (atoms and selectors)–the point of Redux is as an ecosystem, and the 'redux' way of handling data withing an app, along with all the tools surrounding it.

Recoil does show a lot of promise on its own though. I was able to get it up and running with resonable effort and the API is also well documented with lot of examples to help grasp how Recoil is meant to be used.

Conclusion

I had to try Recoil because it felt a lot more compatible with how I generally write React code, and it certainly shows a lot of promise on that front. It felt easier to compose a state management system that does precisely what I needed.

Consider this example that handles the state of blocks. We create an atomFamily to which we can provide an array of functions (/effects) that can act like middleware for your store.

const loggingEffect =
  blockId =>
  ({ setSelf, onSet }) => {
    onSet((newValue, oldValue) => {
      console.log("Updating block", blockId, { oldValue, newValue })
    })
  }

const blockStateFamily = atomFamily({
  key: "BlockStates",
  default: null,
  effects_UNSTABLE: blockId => [loggingEffect(blockId)],
})

export default blockStateFamily

You can simply access and update the state just like when you'd use useState... see what I mean by familiar?

const [block, setBlock] = useRecoilState(blockStateFamily(blockId))

tldr; I'd use Redux today, but look forward to being able to work with Recoil as it matures.