Until recently I was able to get away with React Context for managing shared state between comonents. It's an ideal solution for most small to medium projects that just have a few bits of state being 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 trying to encapsulate more than a few variables into a Context provider.

It's even more confusing if the state is being updated from multiple components in the app, or to further complcate 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

Let's start with a question: 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, to make your code more manageable; making it less error-prone and easier to collaborate on

This post is primarily about the the state of Redux in 2022, however I'll talk a little about the newer Recoil JS library that takes a more react-ish approach to state management. Personally I was drawn towards Recoil becuase it simply 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 also implement Recoil to find out if it actually works that well. (Spoiler; it does!)


The redux ecosystem in 2022

The core ecosystem has come a long way. Redux toolkit now provides a few packages with a lot of good defaults for getting redux setup-and-running quickly.

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

Redux is still the wild-west of state management tools, meaning, it's very powerful, but be prepared to figure a lot of 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 describe 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 covered in good detail within the documentation.

Redux Toolkit now provides better ways to get going quickly; to begin with, the createSlice API that generates action creators and action types based on the reducers and state defined. It is also quite useful that createSlice uses Immer under the hood so that you can write mutating updates (eg: 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 complicated the use-case.

What is Recoil?

It's another state management system for React by Facebook Opensource. It follows a react-ish 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, 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 exactly 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.