What is Jotai?

A lot of state management libraries for React are popping up every day. One such relatively new library is Jotai - Jotai v1 was announced on Jun 14, 2021 on GitHub and Jotai v2 on February 1st, 2023. It has been gaining traction ever since at an impressive rate, as you can see in the graph below:

Source: https://npmtrends.com/jotai
Source: https://npmtrends.com/jotai

By the way, you can ignore that long downward trend as that is on Christmas day.

Jotai is quite contrasting from the most popular state management library, Redux, because Jotai uses a different architecture pattern for state management. Jotai was inspired by Recoil and makes use of a similar pattern for state management as Recoil, called Atomic state, the core concept of which the entire library is made out of.

No no, you haven’t accidentally landed in a scientific blog, it’s not THAT atom. But, it is indeed inspired by that atom.

💡Different State Management types found

Flux
React Global store is based on the Flux architecture pattern. Comprised of major parts such as dispatchers, stores, actions, reducers, and views, it follows a centralized application state. The store is subscribed to the dispatchers which are in turn called by the actions to update the state. Uses a top-down approach. (State is one object)
Eg:- Redux, Zustand

Context
React context is not exactly a state management ‘tool’. It is a natively available mechanism. Instead of manually passing down props through each level, data is globally accessible through the component tree.

Proxy
Also referred to as “Magic Store”. This type of state management uses the proxy pattern introduced in ES6. Basically, it uses a proxy object which enables you to create an object instead of the original object but you can manipulate it by using fundamental object operations such as getting, setting, defining properties, etc. So the state is wrapped in a proxy and components subscribe to it to get notifications of state changes.
Eg:- MobX, Valtio

Atomic Model
Uses a bottom-up approach. The state is built by combining atoms, and the state can be shared between components by the components subscribing to the defined atoms and listening to changes. The state is stored internally, within the React component tree.
Eg:- Recoil, Jotai, NanoStore

What is an Atom?

Definition

An atom is the smallest possible and isolated unit of state and cannot be broken down further.

How to share state between components in Jotai

You can create an atom and use it in different components like this:

import { atom , useAtom, useAtomValue, useSetAtom } from 'jotai'

// creating an atom (Referred to as atom config)
const nameAtom = atom('John')

const ReadWriteNameApp = () => {
  // using the atom. It is similar to a useState hook:
  const [name, setName] = useAtom(nameAtom)

  return (
    <>
      My current name is {name}.
      <button onClick={() => {setName('Peter')}}>
        Change Name
      </button>
    <>
  )
}

const ReadNameApp = () => {
	// you can also only do a read
  const name = useAtomValue(nameAtom)

  return (
    <>
      My name is {name}.
    <>
  )
}

const WriteNameApp = () => {
 // or you can simply do only a write
  const setName = useSetAtom(nameAtom)

  return (
    <>
      <button onClick={() => {setName('Jack')}}>
        Change Name
      </button>
    <>
  )
}

Note that when you only need to do either a read or a write, using useAtomValue or using useSetAtom separately will optimize re-renders, instead of using useAtom.

Image Credits: https://twitter.com/clairebolton_/status/1319046184250593281?s=20&t=CxcvisnTkNZM7Insl9IQ7A
Image Credits: https://twitter.com/clairebolton_/status/1319046184250593281?s=20&t=CxcvisnTkNZM7Insl9IQ7A

Fell asleep reading the blog? I hope that woke you up!

FUN FACT #1

Jotai is made by the same creators of Zustand AND Valtio! Oh, and react-spring.

Why you should give Jotai a try

FUN FACT #2

”Jotai was born to solve extra re-render issues in React.” - Jotai Docs

  • No unnecessary or extra re-renders, unlike React Context.
  • Very minimalist API and lightweight library. Its bundle size is only 6.3kB (Version 2), while its minimal core API is only 2kb.
  • State flexibility
  • Good performance
  • No boilerplate code, easy to set up. No need to set up stores, actions, or wrap with providers, or handle consumers
  • Beginner friendly
  • A super lightweight bundle
  • You don’t have to deal with memoization anymore
  • Can avoid prop drilling
  • Typescript oriented
  • Jotai supports React Suspense!
  • Jotai supports Async operations.
  • Jotai also supports atoms to use as local storage/session storage through utilities.
  • You can use Jotai instead of useState + React Context
  • Supports code splitting
  • Jotai’s Atomic state and other utilities suit drawing-based apps well.
  • Has good documentation and community support
  • I think for a small to medium project you don’t require another library such as react-query (a.k.a tanstack-query) or redux to handle asynchronous operations such as fetch requests as Jotai supports asynchronous behavior. It also has a util called ‘loadable’ if you want more control on handling loading and error states, rather than using Suspense or Error boundaries.
  • Jotai encourages you to use other libraries as well along with Jotai! It has a lot of library integration support, for example, Redux, React-Query, tRPC, Immer, etc. Due to this nature, and due to its atomic nature and minimalistic API as well, it is the popular opinion that Jotai will be there for a long time.
  • Jotai has a ghost for its logo! 👻
💡Garbage Collection

Jotai utilizes automatic garbage collection and hence avoids memory leaks too. That is, when the atom config (the atom definition) is unavailable, its corresponding state value will be garbage collected as well.

garbage-collection-diagram

Ref: Diagram by Daishi Kato

💡Typescript support

const [name, setName] = useState<string>("");
const [name, setName] = useAtom(nameAtom);

Here, the type of the nameAtom is automatically derived by Jotai from its initial value.

💡What is React Suspense?

"Suspense lets your components “wait” for something before they can render" (React Docs)

Jotai fully leverages React Suspense for its async atoms, so if you use them, you have to wrap that component where you are using aysnc atoms with Suspense.

💡Jotai Provider and Store

A Provider provides state for a component sub tree. It is optional to use a Provider, by default it is in Provider less mode (Atoms will use the default state). However, in SSR scenario you need to use a Provider at the root of your App (or subtree). Note that you can have multiple Providers and have different states.

Jotai has a Store API (Introduced in V2 to expose its store interface) by which you can directly manipulate atom values (read/write/subscribe).

 const myStore = createStore()

 const nameAtom = atom('John')  myStore.set(nameAtom , 'Peter')  myStore.sub(nameAtom , () => {   console.log('Listening to changes in nameAtom',   myStore.get(nameAtom))  })  const Root = () => (   <Provider store={myStore}>    <App />   </Provider>  )

A Comparison Between Jotai and Other State Management Libraries

Source: https://twitter.com/dai_shi/status/1381252474682535938?s=20&t=b6TfuhpVloaMhIbJVZvjwQ
Source: https://twitter.com/dai_shi/status/1381252474682535938?s=20&t=b6TfuhpVloaMhIbJVZvjwQ

Jotai Vs Redux

One difference between Redux and Jotai is the amount of boilerplate code (maintaining actions, store, reducers, etc). Even though the redux toolkit lessens the boilerplate code, you still have to set up the store. Jotai has no initial configuration to set up, you can straight away jump into sharing state between components. Another major difference lies in the architecture: while Redux stores the entire state in a single object, Jotai breaks the state into atoms.

In Redux, store mutation, especially nested store modification is tricky to manage, for which you have to depend on some library such as Immer. However, with Jotai, it is easy to manage state complexity thanks to derived atoms.

Jotai vs Zustand

Both Jotai and Zustand are simplistic and minimalistic libraries. Zustand is similar to Redux but with minimum boilerplate code. The main difference lies in the architecture. Like Redux, Zustand has a single store, that is the entire state is stored in a single object. (You can still have more than one store.) Zustand’s design is to have the store at the module level (external store) more than the context level while with Jotai it is the opposite, hence Jotai supports concurrency mode better. However, you can still use both approaches for either library. Jotai optimizes renders automatically through atom dependency whereas in Zustand you have to manually optimize renders with selectors.

Jotai vs Valtio

Let’s compare Jotai vs Valtio rather than Jotai vs MobX, as MobX and Valtio have a similar underlying base concept of using proxy-based state management. The mental model of Jotai is closer to React than Valtio (or other proxy-based libraries). Creator of Jotai and Valtio, Daishi Kato recommends using Jotai if you want a react component-centered application and to use Valtio if you want a data-centric application. What this actually means is that the state resides inside react in Jotai while the state resides outside of react (module level) in Valtio (Similar to Zustand/Redux). Jotai is also more react-based so it is familiar to use, while Valtio needs a bit of getting used to if you are not familiar with object-oriented programming.

Jotai vs Recoil

You could say Zustand is a good alternative to Redux, and Valtio is an alternative to MobX. Similarly, Jotai is a good alternative to Recoil. Both have the same underlying state management pattern - atomic state, and the state is stored internally. Recoil was developed by Facebook and still remains an ‘experimental’ state management library while Jotai is not in an experimental mode. The bundle size of Jotai (6.3kb minified) is significantly lesser than the size of Recoil (79.1kb minified - bundlephobia).

The obvious difference between the two is that in Recoil you have to specify a key property for the atom you are defining for identity and as the state grows big it becomes a bit tricky to keep all the naming unique.

Defining an Atom in Recoil:

const fontColorAtom = atom({
  key: "fontColorAtom",
  default: "blue",
})

And in Jotai:

const fontColorAtom = atom("blue")

That said, Jotai depends on atom object referential identities.

While Recoil has separate functions for atoms and selectors, Jotai uses ‘atom’ for both. A selector in Jotai is known as a ‘derived’ atom. Recoil, however, seems to have more features to support state serialization (storing state in storage, server, or URL).

Jotai vs React Context

In React Context, to handle unnecessary re-renders, you need to provide many context providers and that could lead to the famous ‘Provider Hell’, so you might need a memoization technique to solve that. But with Jotai, since renders are optimized based on atom dependency, the need for memoization is eliminated. Jotai API is also much more simple and more minimalistic than using React Context.

Disclaimer: I don’t have much experience with using all these libraries, so please try them out for yourself before selecting a library. It all depends on your use case.

Other References

https://jotai.org/

https://twitter.com/0xca0a/status/1328742919872933888?s=20&t=5McCe0vOoKFBbLYCuPM42g

https://docs.pmnd.rs/zustand/getting-started/comparison

https://github.com/pmndrs/jotai/discussions/849

https://blog.axlight.com/posts/when-i-use-valtio-and-when-i-use-jotai/

https://blog.logrocket.com/jotai-vs-recoil-what-are-the-differences/

https://twitter.com/clairebolton_/status/1319046184250593281?s=20&t=CxcvisnTkNZM7Insl9IQ7A