DEV Community

Cover image for An introduction to atomic state management libraries in React
Tom Lienard
Tom Lienard

Posted on

An introduction to atomic state management libraries in React

Introduction

Atomic state management libraries are growing. Fast. As you can see in this graph from npmtrends, the two most famous libraries Recoil and Jotai were almost unknown last year, and now count respectively 240k and 35k downloads per week:

Jotai VS Recoil

I've also open-sourced a new atomic library called Particule, which has some new interesting features such as custom atom functions with hooks.

But what is atomic state management?

Ha, that's a good question. From Recoil's docs:

Atoms are units of state. They're updateable and subscribable: when an atom is updated, each subscribed component is re-rendered with the new value.

An atom represents a piece of state that you can read and update anywhere in your application. Think of it as a useState that can be shared in any component.

This approach provides many benefits, mainly:

Avoid unwanted re-renders and computations

You won't anymore pass state values and update functions via props, nor trigger the whole tree of components from a context's consumer. Only components subscribed to the atom's value will update.

Take a look at this example using Particule:

const textAtom = atom('Hello world!')

function Text() {
  const text = useGetAtom(textAtom)

  return <p>{text}</p>
}

// Won't re-render!
function Button() {
  const setText = useSetAtom(textAtom)

  return <button onClick={() => setText('Updated!')}>Update</button>
}

// Won't re-render!
export default function App() {
  return (
    <>
      <Text />
      <Button />
    </>
  )
Enter fullscreen mode Exit fullscreen mode

Only <Text /> will re-render, even if <Button /> also uses the atom. But there's a difference between the two: <Button /> isn't subscribed to updates, because it uses useSetAtom and only retrieves a setter function (similar to the one in useState. On the contrary, <Text /> is subscribed to updates because it uses useGetAtom to retrieve the value.

Compose atom from other atoms

Derived (or composed) atoms are atoms made from other atoms. They subscribe to each atom that they depend on, and such automatically trigger a re-render when needed.

This can be made using selectors in Recoil, and is even simpler in Jotai and Particule. This example is made with Particule:

const eurosAtom = atom(10)
const dollarsAtom = atom(get => get(eurosAtom) * 1.15)

function App() {
  const [euros, setEuros] = useAtom(eurosAtom)
  const [dollars, setDollars] = useAtom(dollarsAtom)

  return (
    <>
      <input onChange={({ target }) => setEuros(target.value)} value={euros} />
      <input onChange={({ target }) => setDollars(target.value)} value={dollars} />
    </>
  )
}
Enter fullscreen mode Exit fullscreen mode

When eurosAtom changes, dollarsAtom is re-calculated since it is subscribed using get and re-render the component once.

There are many other interesting topics with atomic state management libraries, such as <Suspense /> support for async, helper atom functions to add new functionalities...

So feel free to comment down below if you want more articles on this, and you can check out the GitHub repository of the libraries I mentioned:

Top comments (3)

Collapse
 
rtyurin profile image
Ramin Tyurin

Could also recommend Effector library (effector.dev/), which is framework agnostic, but primarily used with react.

Collapse
 
alanxtreme profile image
Alan Daniel

Recoil ftw

Collapse
 
martyroque profile image
Marty Roque

I would also like to recommend App's Digest, a simple, atomic state management library primarily for React.