# Technical Documentation: pmndrs/jotai

> ℹ️ **Provenance:** Multi-Tier Ingestion · [CodeWiki Reference](https://codewiki.google/github.com/pmndrs/jotai)

### Overview (`README.md`)

<br>




<br>

visit [jotai.org](https://jotai.org) or `npm i jotai`

[](https://github.com/pmndrs/jotai/actions/workflows/test.yml?query=branch%3Amain)
[](https://bundlephobia.com/result?p=jotai)
[](https://www.npmjs.com/package/jotai)
[](https://www.npmjs.com/package/jotai)
[](https://discord.gg/poimandres)
[](https://opencollective.com/jotai)

Jotai scales from a simple useState replacement to an enterprise TypeScript application.

- Minimal core API (2kb)
- Many utilities and extensions
- No string keys (compared to Recoil)

Examples: [Demo 1](https://codesandbox.io/s/jotai-demo-47wvh) |
[Demo 2](https://codesandbox.io/s/jotai-demo-forked-x2g5d)

### First, create a primitive atom

An atom represents a piece of state. All you need is to specify an initial
value, which can be primitive values like strings and numbers, objects, and
arrays. You can create as many primitive atoms as you want.

```jsx
import { atom } from 'jotai'

const countAtom = atom(0)
const countryAtom = atom('Japan')
const citiesAtom = atom(['Tokyo', 'Kyoto', 'Osaka'])
const mangaAtom = atom({ 'Dragon Ball': 1984, 'One Piece': 1997, Naruto: 1999 })
```

### Use the atom in your components

It can be used like `React.useState`:

```jsx
import { useAtom } from 'jotai'

function Counter() {
  const [count, setCount] = useAtom(countAtom)
  return (
    <h1>
      {count}
      <button onClick={() => setCount((c) => c + 1)}>one up</button>
      ...
```

### Create derived atoms with computed values

A new read-only atom can be created from existing atoms by passing a read
function as the first argument. `get` allows you to fetch the contextual value
of any atom.

```jsx
const doubledCountAtom = atom((get) => get(countAtom) * 2)

function DoubleCounter() {
  const [doubledCount] = useAtom(doubledCountAtom)
  return <h2>{doubledCount}</h2>
}
```

### Creating an atom from multiple atoms

You can combine multiple atoms to create a derived atom.

```jsx
const count1 = atom(1)
const count2 = atom(2)
const count3 = atom(3)

const sum = atom((get) => get(count1) + get(count2) + get(count3))
```

Or if you like fp patterns ...

```jsx
const atoms = [count1, count2, count3, ...otherAtoms]
const sum = atom((get) => atoms.map(get).reduce((acc, count) => acc + count))
```

### Derived async atoms [<img src="https://img.shields.io/badge/-needs_suspense-black" alt="needs suspense" />](https://react.dev/reference/react/Suspense)

You can make the read function an async function too.

```jsx
const urlAtom = atom('https://json.host.com')
const fetchUrlAtom = atom(async (get) => {
  const response = await fetch(get(urlAtom))
  return await response.json()
})

function Status() {
  // Re-renders the component after urlAtom is changed and the async function above concludes
  const [json] = useAtom(fetchUrlAtom)
  ...
```

### You can create a writable derived atom

Specify a write function at the second argument. `get` will return the current
value of an atom. `set` will update the value of an atom.

```jsx
const decrementCountAtom = atom(
  (get) => get(countAtom),
  (get, set, _arg) => set(countAtom, get(countAtom) - 1)
)

function Counter() {
  const [count, decrement] = useAtom(decrementCountAtom)
  return (
    <h1>
      {count}
      <button onClick={decrement}>Decrease</button>
      ...
```

### Write only derived atoms

Just do not define a read function.

```jsx
const multiplyCountAtom = atom(null, (get, set, by) =>
  set(countAtom, get(countAtom) * by),
)

function Controls() {
  const [, multiply] = useAtom(multiplyCountAtom)
  return <button onClick={() => multiply(3)}>triple</button>
}
```

### Async actions

Just make the write function an async function and call `set` when you're ready.

```jsx
const fetchCountAtom = atom(
  (get) => get(countAtom),
  async (_get, set, url) => {
    const response = await fetch(url)
    set(countAtom, (await response.json()).count)
  }
)

function Controls() {
  const [count, compute] = useAtom(fetchCountAtom)
  return (
    <button onClick={() => compute('http://count.host.com')}>compute</button>
    ...
```

### Note about functional programming

Jotai's fluid interface is no accident — atoms are monads, just like promises!
Monads are an [established](<https://en.wikipedia.org/wiki/Monad_(functional_programming)>)
pattern for modular, pure, robust and understandable code which is [optimized for change](https://overreacted.io/optimized-for-change/).
Read more about [Jotai and monads.](https://jotai.org/docs/basics/functional-programming-and-jotai)

## Links

- [website](https://jotai.org)
- [documentation](https://jotai.org/docs)
- [course](https://egghead.io/courses/manage-application-state-with-jotai-atoms-2c3a29f0)

---

### Overview (`website/README.md`)

## Getting Started

Install the dependencies:

```bash
pnpm install --ignore-workspace
```

Make a cache directory:

```bash
mkdir .cache
```

Run the development server:

```bash
pnpm run dev
```

Open [http://localhost:9000](http://localhost:9000) with your browser to see the result.

---

### Overview (`examples/hacker_news/README.md`)

# Hacker News [](https://stackblitz.com/github/pmndrs/jotai/tree/main/examples/hacker_news)

## Description

Browse Hacker News items with Jotai. Click the arrow button to load the next item.

## Set up locally

```bash
git clone https://github.com/pmndrs/jotai

# install project dependencies & build the library
cd jotai && pnpm install

# move to the examples folder & install dependencies
cd examples/hacker_news && pnpm install

# start the dev server
pnpm dev
```

## Set up on `StackBlitz`

Link: https://stackblitz.com/github/pmndrs/jotai/tree/main/examples/hacker_news

---

### Overview (`examples/hello/README.md`)

# Hello [](https://stackblitz.com/github/pmndrs/jotai/tree/main/examples/hello)

## Set up locally

```bash
git clone https://github.com/pmndrs/jotai

# install project dependencies & build the library
cd jotai && pnpm install

# move to the examples folder & install dependencies
cd examples/hello && pnpm install

# start the dev server
pnpm dev
```

## Set up on `StackBlitz`

Link: https://stackblitz.com/github/pmndrs/jotai/tree/main/examples/hello

---

### Overview (`examples/mega-form/README.md`)

# Mega form [](https://stackblitz.com/github/pmndrs/jotai/tree/main/examples/mega-form)

## Set up locally

```bash
git clone https://github.com/pmndrs/jotai

# install project dependencies & build the library
cd jotai && pnpm install

# move to the examples folder & install dependencies
cd examples/mega-form && pnpm install

# start the dev server
pnpm dev
```

## Set up on `StackBlitz`

Link: https://stackblitz.com/github/pmndrs/jotai/tree/main/examples/mega-form

---

### Overview (`examples/starter/README.md`)

# Starter [](https://stackblitz.com/github/pmndrs/jotai/tree/main/examples/starter)

## Set up locally

```bash
git clone https://github.com/pmndrs/jotai

# install project dependencies & build the library
cd jotai && pnpm install

# move to the examples folder & install dependencies
cd examples/starter && pnpm install

# start the dev server
pnpm dev
```

## Set up on `StackBlitz`

Link: https://stackblitz.com/github/pmndrs/jotai/tree/main/examples/starter

---

### Overview (`examples/text_length/README.md`)

# Text Length [](https://stackblitz.com/github/pmndrs/jotai/tree/main/examples/text_length)

## Description

Count the length and show the uppercase of any text.

## Set up locally

```bash
git clone https://github.com/pmndrs/jotai

# install project dependencies & build the library
cd jotai && pnpm install

# move to the examples folder & install dependencies
cd examples/text_length && pnpm install

# start the dev server
pnpm dev
```

## Set up on `StackBlitz`

Link: https://stackblitz.com/github/pmndrs/jotai/tree/main/examples/text_length

---

### Overview (`examples/todos/README.md`)

# Todos [](https://stackblitz.com/github/pmndrs/jotai/tree/main/examples/todos)

## Description

Create a todo list, mark tasks as completed, and switch between `Completed` and `Incomplete` to filter items.

## Set up locally

```bash
git clone https://github.com/pmndrs/jotai

# install project dependencies & build the library
cd jotai && pnpm install

# move to the examples folder & install dependencies
cd examples/todos && pnpm install

# start the dev server
pnpm dev
```

## Set up on `StackBlitz`

Link: https://stackblitz.com/github/pmndrs/jotai/tree/main/examples/todos

---

### Overview (`examples/todos_with_atomFamily/README.md`)

# Todos with atomFamily [](https://stackblitz.com/github/pmndrs/jotai/tree/main/examples/todos_with_atomFamily)

> **⚠️ Note:** `atomFamily` from `jotai/utils` is deprecated and will be removed in v3. For new projects, please use the [`jotai-family`](https://github.com/jotaijs/jotai-family) package instead.

## Description

Implement a todo list using atomFamily and `localStorage`. You can save your todo list by clicking `Save to localStorage`, then restore it by clicking `Load from localStorage`.

## Set up locally

```bash
git clone https://github.com/pmndrs/jotai

# install project dependencies & build the library
cd jotai && pnpm install

# move to the examples folder & install dependencies
cd examples/todos_with_atomFamily && pnpm install

# start the dev server
pnpm dev
```

## Set up on `StackBlitz`

Link: https://stackblitz.com/github/pmndrs/jotai/tree/main/examples/todos_with_atomFamily

---

### Index (`docs/index.mdx`)

---
title: Documentation
description: Table of contents
nav: 0
---

Welcome to the Jotai v2 documentation! Jotai's atomic approach to global React state management scales from a simple `useState` replacement to an enterprise application with complex requirements.

## Features

- Minimal core API (2kb)
- Many utilities and extensions
- TypeScript oriented
- Works with Next.js, Waku, Remix, and React Native

## Core

Jotai has a very minimal API, exposing only a few exports from the main `jotai` bundle. They are split into four categories below.

<TOC section="core" />

## Utilities

Jotai also includes a `jotai/utils` bundle with a variety of extra utility functions. One example is `atomWithStorage`, which includes localStorage persistence and cross browser tab synchronization.

<TOC section="utilities" />

## Extensions

Jotai has many officially maintained extensions including `atomWithQuery` for React Query and `atomWithMachine` for XState, among many others.

<TOC section="extensions" />

## Third-party

Beyond the official extensions, there are many third-party community packages as well.

<TOC section="third-party" />

## Tools

Use SWC and Babel compiler plugins for React Fast Refresh support and debugging labels. This creates the best developer experience when using a React framework such as Next.js or Waku.

<TOC section="tools" />

## Basics

Learn the basic concepts of the library, discover how it compares with others, and see usage examples.

<TOC section="basics" />

## Guides

Guides can help with use common cases such as TypeScript, React frameworks, and basic patterns.

<TOC section="guides" />

## Recipes

Recipes can help with more advanced patterns.

<TOC section="recipes" />

---

### Basics Comparison (`docs/basics/comparison.mdx`)

---
title: Comparison
nav: 7.02
---

Jotai was born to solve extra re-render issues in React.
An extra re-render is when the render process produces the same UI result,
where users won't see any differences.

To tackle this issue with React context (useContext + useState),
one would require many contexts and face some issues.

- Provider hell: It's likely that your root component has many context providers, which is technically okay, and sometimes desirable to provide context in different subtree.
- Dynamic addition/deletion: Adding a new context at runtime is not very nice, because you need to add a new provider and its children will be re-mounted.

Traditionally, a top-down solution to this is to use a selector function.
The [use-context-selector](https://github.com/dai-shi/use-context-selector) library is one example.
The issue with this approach is the selector function needs to return
referentially equal values to prevent re-renders, and this often requires a memoization technique.

Jotai takes a bottom-up approach with the atomic model, inspired by [Recoil](https://recoiljs.org/).
One can build state combining atoms, and optimize renders based on atom dependency.
This avoids the need for memoization.

Jotai has two principles.

- Primitive: Its basic API is simple, like `useState`.
- Flexible: Atoms can derive another atom and form a graph. Atoms can also be updated by another arbitrary atom. It allows abstracting complex state models.

### How is Jotai different from useContext of React?

Jotai's core API is minimalistic and makes it easy to build utilities based upon it.

#### Analogy

You can view Jotai as a drop-in replacement to `useContext`. Except Jotai is aiming for simplicity, minimalistic API and can do much more than `useContext` & `useState`.

#### Usage difference

We can see how we used to share data to children, compared to how we do it with Jotai. But let's use a real-world example where we have multiple `Context` in our app.

```jsx
// 1. useState local state
const Component = () => {
  const [state, setState] = useState(0)
}

// 2. Lift local state up and share it via context
const StateContext = createContext()
const Parent = ({ children }) => {
  return (
    <StateContext.Provider value={useState(0)}>
      {children}
    </StateContext.Provider>
  )
}
const Component = () => {
  const [state, setState] = useContext(StateContext)
}

// 3. Have multiple states and contexts
const State1Context = createContext()
const State2Context = createContext()
const Parent = ({ children }) => (
  <State1Context.Provider value={useState(0)}>
    <State2Context.Provider value={useState(0)}>
      {children}
    </State2Context.Provider>
  </State1Context.Provider>
)
const Component1 = () => {
  const [state, setState] = useContext(State1Context)
}
const Component2 = () => {
  const [state, setState] = useContext(State2Context)
}
```

Now let's see how Jotai simplify it for us. You can just use atoms instead of multiple `Context`.

```jsx
import { Provider, atom, useAtom } from 'jotai'
const atom1 = atom(0)
const atom2 = atom(0)
// Optional: you can use Provider's just like useContext,
// ...but if you only need one,
// ...you can just omit it and Jotai will use a default one (called Provider-less mode).
const Parent = ({ children }) => {
  return <Provider>{children}</Provider>
}
const Component1 = () => {
  const [state, setState] = useAtom(atom1)
}
const Component2 = () => {
  const [state, setState] = useAtom(atom2)
}
```

### How is Jotai different from Zustand?

#### Name

Jotai means "state" in Japanese.
Zustand means "state" in German.

#### Analogy

Jotai is like Recoil.
Zustand is like Redux.

#### Where state resides

To hold states,
Both have stores that can exist either at module level or at context level.
Jotai is designed to be context first, and module second.
Zustand is designed to be module first, and context second.

#### How to structure state

Jotai state consists of atoms (i.e. bottom-up).
Zustand state is one object (i.e. top-down).

#### Technical difference

The major difference is the state model. Zustand is a single store (although you could create multiple separate stores), while Jotai consists of primitive atoms and allows composing them together. In this sense, it's the matter of programming mental model.

#### When to use which

- If you need a replacement for useState+useContext, Jotai fits well.
- If you want a simple module state, Zustand fits well.
- If code splitting is important, Jotai should perform well.
- If you prefer Redux devtools, Zustand is good to go.
- If you want to make use of Suspense, Jotai is the one.

### How is Jotai different from Recoil?

(Disclaimer: the author is not very familiar with Recoil, this may be biased and inaccurate.)

#### Developer

- Jotai is developed with collective work by a few developers in Poimandres (formerly react-spring) org.
- Recoil is developed by a team at Facebook.

#### Basis

- Jotai is focusing on primitive APIs for easy learning, and it's unopinionated. (The same philosophy with Zustand)
- Recoil is all-in-one, and it has various cache strategies.

#### Technical difference

- Jotai depends on atom object referential identities.
- Recoil depends on atom string keys.

#### When to use which

- If you want to learn something new, either should work.
- If you like Zustand, Jotai would also be pleasant.
- If you need React Context alternatives, Jotai comes with enough features.
- If you need to read and write atoms outside React, Jotai provides store API.
- If you would try to create a new library, Jotai might give good primitives.
- Otherwise, both are pretty similar about the general goals and basic techniques, so please try both and share your feedback with us.

---

### Basics Concepts (`docs/basics/concepts.mdx`)

---
title: Concepts
nav: 7.01
---

Jotai is a library that will make you return to the basics of React development & keep everything simple.

### From scratch

Before trying to compare Jotai with what we may have known previously, let's just dive straight into something very simple.

The React world is very much like our world, it's a big set of small entities, we call them components, and we know that they have their own state. Structuring your components to interact altogether will create your app.

Now, the Jotai world also has its small entities, atoms, and they also have their state. Composing atoms will create your app state!

Jotai considers anything to be an atom, so you may say: `Huh, I need objects and arrays, filter them and then sort them out`.
And here's the beauty of it, Jotai gracefully lets you create dumb atoms derived from even more dumb atoms.

If, for example, I have a page with 2 tabs: online friends and offline friends.
I will have 2 atoms simply derived from a common, dumber source.

```js
const dumbAtom = atom([{ name: 'Friend 1', online: false }])
const onlineAtom = atom((get) => get(dumbAtom).filter((item) => item.online))
const offlineAtom = atom((get) => get(dumbAtom).filter((item) => !item.online))
```

And you could keep going on complexity forever.

Another incredible feature of Jotai is the built-in ability to suspend when using asynchronous atoms. This is a relatively new feature that needs more experimentation, but is definitely the future of how we will build React apps. [Check out the docs](https://react.dev/blog/2022/03/29/react-v18#new-suspense-features) for more info.

---

### Basics Functional Programming And Jotai (`docs/basics/functional-programming-and-jotai.mdx`)

---
title: Functional programming and Jotai
nav: 7.04
---

### Unexpected similarities

If you look at getter functions long enough, you may see a striking resemblance
to a certain JavaScript language feature.

```tsx
const nameAtom = atom('Visitor')
const countAtom = atom(1)
const greetingAtom = atom((get) => {
  const name = get(nameAtom)
  const count = get(countAtom)
  return (
    <div>
      Hello, {name}! You have visited this page {count} times.
    </div>
  )
})
```

Compare that code with `async`–`await`:

```tsx
const namePromise = Promise.resolve('Visitor')
const countPromise = Promise.resolve(1)
const greetingPromise = (async function () {
  const name = await namePromise
  const count = await countPromise
  return (
    <div>
      Hello, {name}! You have visited this page {count} times.
    </div>
  )
})()
```

This similarity is no coincidence. Both atoms and promises are **Monads**†, a
concept from functional programming. The syntax used in both `greetingAtom` and
`greetingPromise` is known as **do-notation**, a syntax sugar for the plainer
monad interface.

### About monads

The monad interface is responsible for the fluidity of the atom and promise
interfaces. The monad interface allowed us to define `greetingAtom` in terms of
`nameAtom` and `countAtom`, and allowed us to define `greetingPromise` in terms
of `namePromise` and `countPromise`.

If you're curious, a structure (like `Atom` or `Promise`) is a monad if you can
implement the following functions for it. A fun exercise is trying to implement
`of`, `map` and `join` for Arrays.

```ts
type SomeMonad<T> = /* for example... */ Array<T>
declare function of<T>(plainValue: T): SomeMonad<T>
declare function map<T, V>(
  anInstance: SomeMonad<T>,
  transformContents: (contents: T) => V,
): SomeMonad<V>
declare function join<T>(nestedInstances: SomeMonad<SomeMonad<T>>): SomeMonad<T>
```

The shared heritage of Promises and Atoms means many patterns and best-practices
can be reused between them. Let's take a look at one.

### Sequencing

When talking about callback hell, we often mention the boilerplate, the
indentation and the easy-to-miss mistakes. However, plumbing a single async
operation into another single async operation was not the end of the callback
struggle. What if we made four network calls and needed to wait for them all?
A snippet like this was common:

```ts
const nPending = 4
const results: string[]
function callback(err, data) {
  if (err) throw err
  results.push(data)
  if (results.length === nPending) {
    // do something with results...
  }
}
```

But what if the results have different types? and the order was important? Well,
we'd have a lot more frustrating work to do! This logic would be duplicated at
each usage, and would be easy to mess up. Since ES6, we simply call `Promise.all`:

```ts
declare function promiseAll<T>(promises: Array<Promise<T>>): Promise<Array<T>>
```

`Promise.all` "rearranges" `Array` and `Promise`. It turns out this concept,
_sequencing_, can be implemented for all monad–_Traversable_ pairs. Many kinds
of collections are Traversables, including Arrays. For example, this is a case
of sequencing specialized for atoms and arrays:

```ts
function sequenceAtomArray<T>(atoms: Array<Atom<T>>): Atom<Array<T>> {
  return atom((get) => atoms.map(get))
}
```

### Culmination

Monads have been an interest to mathematicians for 60 years, and to programmers
for 40. There are many resources out there on patterns for monads. Take a look
at them! Here are a select few:

- [_Inventing Monads_](https://stopa.io/post/247) by Stepan Parunashvili
- [_How Monads Solve Problems_](https://thatsnomoon.dev/posts/ts-monads/) by ThatsNoMoon
- Wiki page [list of monad tutorials](https://wiki.haskell.org/Monad_tutorials_timeline)
- [Typeclassopedia](https://wiki.haskell.org/Typeclassopedia) (for the curious)

Learning a neat trick on using promises may well translate to atoms, as
`Promise.all` and `sequenceAtomArray` did. Monads are not magic, just unusually
useful, and a tool worth knowing.

---

_Notes_

**[†]** The ES6 Promise is not a completely valid monad because it cannot nest other
Promises, e.g. `Promise<Promise<number>>` is semantically equivalent to
`Promise<number>`. This is why Promises only have a `.then`, and not both a
`.map` and `.flatMap`. ES6 Promises are probably more properly described as
"monadic" rather than as monads.

Unlike ES6 Promises, the ES6 Array is a completely lawful monad.

---

### Basics Showcase (`docs/basics/showcase.mdx`)

---
title: Showcase
nav: 7.03
---

- Text Length example [](https://githubbox.com/pmndrs/jotai/tree/main/examples/text_length)

  Count the length and show the uppercase of any text.

- Hacker News example [](https://githubbox.com/pmndrs/jotai/tree/main/examples/hacker_news)

  Demonstrate a news article with Jotai, hit next to see more articles.

- Todos example [](https://githubbox.com/pmndrs/jotai/tree/main/examples/todos)

  Record your todo list by typing them into this app, check them off if you have completed the task, and switch between `Completed` and `Incompleted` to see the status of your task.

- Todos example with atomFamily and localStorage [](https://githubbox.com/pmndrs/jotai/tree/main/examples/todos_with_atomFamily)

  Implement a todo list using atomFamily and localStorage. You can store your todo list to localStorage by clicking `Save to localStorage`, then remove your todo list and try restoring them by clicking `Load from localStorage`.

- Clock with Next.js [](https://codesandbox.io/s/nextjs-with-jotai-5ylrj)

  An UTC time electronic clock implementation using Next.js and Jotai.

- Tic Tac Toe game [](https://codesandbox.io/s/jotai-tic-tac-6cg3h)

  A game of tic tac toe implemented with Jotai.

- React Three Fiber demo [](https://codesandbox.io/s/jotai-r3f-fri9d)

  A simple demo to use Jotai with react-three-fiber

---

### Core Atom (`docs/core/atom.mdx`)

---
title: atom
description: This doc describes core `jotai` bundle.
nav: 2.01
keywords: atom,primitive,derived,debug,label,onmount
---

## atom

The `atom` function is to create an atom config.
We call it "atom config" as it's just a definition and it doesn't yet hold a value.
We may also call it just "atom" if the context is clear.

An atom config is an immutable object. The atom config object doesn't hold a value. The atom value exists in a store.

To create a primitive atom (config), all you need is to provide an initial value.

```js
import { atom } from 'jotai'

const priceAtom = atom(10)
const messageAtom = atom('hello')
const productAtom = atom({ id: 12, name: 'good stuff' })
```

You can also create derived atoms. We have three patterns:

- Read-only atom
- Write-only atom
- Read-Write atom

To create derived atoms, we pass a read function and an optional write function.

```js
const readOnlyAtom = atom((get) => get(priceAtom) * 2)
const writeOnlyAtom = atom(
  null, // it's a convention to pass `null` for the first argument
  (get, set, update) => {
    // `update` is any single value we receive for updating this atom
    set(priceAtom, get(priceAtom) - update.discount)
    // or we can pass a function as the second parameter
    // the function will be invoked,
    //  receiving the atom's current value as its first parameter
    set(priceAtom, (price) => price - update.discount)
  },
)
const readWriteAtom = atom(
  (get) => get(priceAtom) * 2,
  (get, set, newPrice) => {
    set(priceAtom, newPrice / 2)
    // you can set as many atoms as you want at the same time
  },
)
```

`get` in the read function is to read the atom value.
It's reactive and read dependencies are tracked.

`get` in the write function is also to read atom value, but it's not tracked.
Furthermore, it can't read unresolved async values in Jotai v1 API.

`set` in the write function is to write atom value.
It will invoke the write function of the target atom.

### Note about creating an atom in render function

Atom configs can be created anywhere, but referential equality is important.
They can be created dynamically too.
To create an atom in render function, `useMemo` or `useRef` is required to get a stable reference. If in doubt about using `useMemo` or `useRef` for memoization, use `useMemo`.
Otherwise, it can cause infinite loop with `useAtom`.

```js
const Component = ({ value }) => {
  const valueAtom = useMemo(() => atom({ value }), [value])
  // ...
}
```

### Signatures

```ts
// primitive atom
function atom<Value>(initialValue: Value): PrimitiveAtom<Value>

// read-only atom
function atom<Value>(read: (get: Getter) => Value): Atom<Value>

// writable derived atom
function atom<Value, Args extends unknown[], Result>(
  read: (get: Getter) => Value,
  write: (get: Getter, set: Setter, ...args: Args) => Result,
): WritableAtom<Value, Args, Result>

// write-only derived atom
function atom<Value, Args extends unknown[], Result>(
  read: Value,
  write: (get: Getter, set: Setter, ...args: Args) => Result,
): WritableAtom<Value, Args, Result>
```

- `initialValue`: the initial value that the atom will return until its value is changed.
- `read`: a function that's evaluated whenever the atom is read. The signature of `read` is `(get) => Value`, and `get` is a function that takes an atom config and returns its value stored in Provider as described below. Dependency is tracked, so if `get` is used for an atom at least once, the `read` will be reevaluated whenever the atom value is changed.
- `write`: a function mostly used for mutating atom's values, for a better description; it gets called whenever we call the second value of the returned pair of `useAtom`, the `useAtom()[1]`. The default value of this function in the primitive atom will change the value of that atom. The signature of `write` is `(get, set, ...args) => Result`. `get` is similar to the one described above, but it doesn't track the dependency. `set` is a function that takes an atom config and a new value which then updates the atom value in Provider. `...args` is the arguments that we receive when we call `useAtom()[1]`. `Result` is the return value of the `write` function.

```js
const primitiveAtom = atom(initialValue)
const derivedAtomWithRead = atom(read)
const derivedAtomWithReadWrite = atom(read, write)
const derivedAtomWithWriteOnly = atom(null, write)
```

There are two kinds of atoms: a writable atom and a read-only atom. Primitive atoms are always writable. Derived atoms are writable if the `write` is specified. The `write` of primitive atoms is equivalent to the `setState` of `React.useState`.

### `debugLabel` property

The created atom config can have an optional property `debugLabel`. The debug label is used to display the atom in debugging. See [Debugging guide](../guides/debugging.mdx) for more information.

Note: While, the debug labels don’t have to be unique, it’s generally recommended to make them distinguishable.

### `onMount` property

The created atom config can have an optional property `onMount`. `onMount` is a function which takes a function `setAtom` and returns `onUnmount` function optionally.

The `onMount` function is called when the atom is subscribed in the provider in the first time,
and `onUnmount` is called when it’s no longer subscribed.
In some cases (like [React strict mode](https://react.dev/reference/react/StrictMode)),
an atom can be unmounted and then mounted immediately.

```js
const anAtom = atom(1)
anAtom.onMount = (setAtom) => {
  console.log('atom is mounted in provider')
  setAtom(c => c + 1) // increment count on mount
  return () => { ... } // return optional onUnmount function
}

const Component = () => {
  // `onMount` will be called when the component is mounted in the following cases:
  useAtom(anAtom)
  useAtomValue(anAtom)

  // however, in the following cases,
  //  `onMount` will not be called because the atom is not subscribed:
  useSetAtom(anAtom)
  useAtomCallback(
    useCallback((get) => get(anAtom), []),
  )
  // ...
}
```

Calling `setAtom` function will invoke the atom’s `write`. Customizing `write` allows changing the behavior.

```js
const countAtom = atom(1)
const derivedAtom = atom(
  (get) => get(countAtom),
  (get, set, action) => {
    if (action.type === 'init') {
      set(countAtom, 10)
    } else if (action.type === 'inc') {
      set(countAtom, (c) => c + 1)
    }
  },
)
derivedAtom.onMount = (setAtom) => {
  setAtom({ type: 'init' })
}
```

### Advanced API

Since Jotai v2, the `read` function has the second argument `options`.

#### `options.signal`

It uses [AbortController](https://developer.mozilla.org/en-US/docs/Web/API/AbortController) so that you can abort async functions.
Abort is triggered before new calculation (invoking `read` function) is started.

How to use it:

```ts
const readOnlyDerivedAtom = atom(async (get, { signal }) => {
  // use signal to abort your function
})

const writableDerivedAtom = atom(
  async (get, { signal }) => {
    // use signal to abort your function
  },
  (get, set, arg) => {
    // ...
  },
)
```

The `signal` value is [AbortSignal](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal).
You can check `signal.aborted` boolean value, or use `abort` event with `addEventListener`.

For `fetch` use case, we can simply pass `signal`.

See the below example for `fetch` usage.

#### `options.setSelf`

⚠️ This internal feature was only available in Jotai v2 and has been removed in v3.

## Stackblitz

<Stackblitz id="vitejs-vite-ccqxix" file="src%2FApp.tsx" />

```tsx
import { Suspense } from 'react'
import { atom, useAtom } from 'jotai'

const userIdAtom = atom(1)
const userAtom = atom(async (get, { signal }) => {
  const userId = get(userIdAtom)
  const response = await fetch(
    `https://jsonplaceholder.typicode.com/users/${userId}?_delay=2000`,
    { signal },
  )
  return response.json()
})

const Controls = () => {
  const [userId, setUserId] = useAtom(userIdAtom)
  return (
    <div>
      User Id: {userId}
      <button onClick={() => setUserId((c) => c - 1)}>Prev</button>
      <button onClick={() => setUserId((c) => c + 1)}>Next</button>
    </div>
  )
}

const UserName = () => {
  const [user] = useAtom(userAtom)
  return <div>User name: {user.name}</div>
}

const App = () => (
  <>
    <Controls />
    <Suspense fallback="Loading...">
      <UserName />
    </Suspense>
  </>
)

export default App
```

---

### Core Provider (`docs/core/provider.mdx`)

---
title: Provider
description: This doc describes core `jotai` bundle.
nav: 2.04
keywords: provider,usestore,ssr
---

## Provider

The `Provider` component is to provide state for a component sub tree.
Multiple Providers can be used for multiple subtrees, and they can even be nested.
This works just like React Context.

If an atom is used in a tree without a Provider,
it will use the default state. This is so-called provider-less mode.

Providers are useful for three reasons:

1. To provide a different state for each sub tree.
2. To accept initial values of atoms.
3. To clear all atoms by remounting.

```jsx
const SubTree = () => (
  <Provider>
    <Child />
  </Provider>
)
```

### Signatures

```ts
const Provider: React.FC<{
  store?: Store
}>
```

Atom configs don't hold values. Atom values reside in separate stores. A Provider is a component that contains a store and provides atom values under the component tree. A Provider works like React context provider. If you don't use a Provider, it works as provider-less mode with a default store. A Provider will be necessary if we need to hold different atom values for different component trees. Provider can take an optional prop `store`.

```jsx
const Root = () => (
  <Provider>
    <App />
  </Provider>
)
```

### `store` prop

A Provider accepts an optional prop `store` that you can use for the Provider subtree.

#### Example

```jsx
const myStore = createStore()

const Root = () => (
  <Provider store={myStore}>
    <App />
  </Provider>
)
```

## useStore

This hook returns a store within the component tree.

```jsx
const Component = () => {
  const store = useStore()
  // ...
}
```

---

### Core Store (`docs/core/store.mdx`)

---
title: Store
description: This doc describes core `jotai` bundle.
nav: 2.03
keywords: store,createstore,getdefaultstore,defaultstore
---

## createStore

This function is to create a new empty store.
The store can be used to pass in `Provider`.

The store has three methods: `get` for getting atom values,
`set` for setting atom values, and `sub` for subscribing to atom changes.

```jsx
const myStore = createStore()

const countAtom = atom(0)
myStore.set(countAtom, 1)
const unsub = myStore.sub(countAtom, () => {
  console.log('countAtom value is changed to', myStore.get(countAtom))
})
// unsub() to unsubscribe

const Root = () => (
  <Provider store={myStore}>
    <App />
  </Provider>
)
```

## getDefaultStore

This function returns a default store that is used in provider-less mode.

```js
const defaultStore = getDefaultStore()
```

---

### Core Use Atom (`docs/core/use-atom.mdx`)

---
title: useAtom
description: This doc describes core `jotai` bundle.
nav: 2.02
keywords: use,useatom,useatomvalue,useatomvalueraw,useatomvaluerawsync,usesetatom,atomvalue,setatom
---

## Choosing a hook

- Read and write an atom: `useAtom`
- Read an atom's value: `useAtomValue`
- Write an atom without reading it (avoids re-renders): `useSetAtom`
- Read without suspending on async atoms: `useAtomValueRaw`
- Same, with no risk of missing an update: `useAtomValueRawSync`

## useAtom

The `useAtom` hook is used to read an atom from the state.
The state can be seen as a WeakMap of atom configs and atom values.

The `useAtom` hook returns the atom value and an update function as a tuple,
just like React's `useState`.
It takes an atom config created with `atom()` as a parameter.

At the creation of the atom config, there is no value associated with it.
Only once the atom is used via `useAtom`, does the initial value get stored in the state.
If the atom is a derived atom, the read function is called to compute its initial value.
When an atom is no longer used, meaning all the components using it are unmounted
and the atom config no longer exists, the value in the state is garbage collected.

```js
const [value, setValue] = useAtom(anAtom)
```

The `setValue` takes just one argument, which will be passed
to the write function of the atom as the third parameter.
The end result depends on how the write function is implemented.
If the write function is not explicitly set, the atom will simply receive the value passed as a parameter to `setValue`.

**Note:** as mentioned in the _atom_ section, referential equality is important when creating atoms,
so you need to handle it properly otherwise it can cause infinite loops.

```js
const stableAtom = atom(0)
const Component = () => {
  const [atomValue] = useAtom(atom(0)) // This will cause an infinite loop since the atom instance is being recreated in every render
  const [atomValue] = useAtom(stableAtom) // This is fine
  const [derivedAtomValue] = useAtom(
    useMemo(
      // This is also fine
      () => atom((get) => get(stableAtom) * 2),
      [],
    ),
  )
}
```

**Note**: Remember that React is responsible for calling your component, meaning it has to be idempotent, ready to be called multiple times. You will often see an extra re-render even if no props or atoms have changed. An extra re-render without a commit is an expected behavior, since it is the default behavior of useReducer in React 18.

### Signatures

```ts
// primitive or writable derived atom
function useAtom<Value, Update>(
  atom: WritableAtom<Value, Update>,
  options?: { store?: Store },
): [Value, SetAtom<Update>]

// read-only atom
function useAtom<Value>(
  atom: Atom<Value>,
  options?: { store?: Store },
): [Value, never]
```

### How atom dependency works

Every time we invoke the "read" function, we refresh the dependencies and dependents.

> The read function is the first parameter of the atom.
> If B depends on A, it means that A is a dependency of B, and B is a dependent on A.

```js
const uppercaseAtom = atom((get) => get(textAtom).toUpperCase())
```

When you create the atom, the dependency will not be present. On first use, we run the read function and conclude that `uppercaseAtom` depends on `textAtom`. So `uppercaseAtom` is added to the dependents of `textAtom`.
When we re-run the read function of `uppercaseAtom` (because its `textAtom` dependency is updated),
the dependency is created again, which is the same in this case. We then remove stale dependents from `textAtom` and replace them with their latest versions.

### Atoms can be created on demand

While the basic examples here show defining atoms globally outside components,
there's no restrictions about where or when we can create an atom.
As long as we remember that atoms are identified by their object referential identity,
we can create them anytime.

If you create atoms in render functions, you would typically want to use
a hook like `useRef` or `useMemo` for memoization. If not, the atom would be re-created each time the component renders.

You can create an atom and store it with `useState` or even in another atom.
See an example in [issue #5](https://github.com/pmndrs/jotai/issues/5).

You can also cache atoms somewhere globally.
See [this example](https://twitter.com/dai_shi/status/1317653548314718208) or
[that example](https://github.com/pmndrs/jotai/issues/119#issuecomment-706046321).

Check [`atomFamily`](../utilities/family.mdx) in utils for parameterized atoms.

## useAtomValue

```jsx
const countAtom = atom(0)

const Counter = () => {
  const setCount = useSetAtom(countAtom)
  const count = useAtomValue(countAtom)

  return (
    <>
      <div>count: {count}</div>
      <button onClick={() => setCount(count + 1)}>+1</button>
    </>
  )
}
```

Similar to the `useSetAtom` hook, `useAtomValue` allows you to access a read-only atom. Nonetheless, it can also be used to access read-write atom's values.

Under the hood, `useAtomValue` is [`useAtomValueRaw`](#useatomvalueraw) plus React's `use()`: it resolves promises and suspends, instead of returning them as-is.

### A subtle mount-timing change in v3

In v2, `useAtomValue` always re-rendered once right after mounting, even without a value change. This caught updates that happened between the initial render and the subscription, for example a value written by a child's `useEffect` (which runs before the parent's).

In v3, that extra render is gone: `useAtomValue` only re-renders on an actual change. It's faster, but it can miss that specific kind of update until the next one. Use [`useAtomValueRawSync`](#useatomvaluerawsync) if you need to catch it.

## useAtomValueRaw

⚠️ This hook is only available since Jotai v3, and it's intended for advanced users.

```jsx
const countAtom = atom(0)

const Counter = () => {
  const count = useAtomValueRaw(countAtom)
  // ...
}
```

`useAtomValueRaw` is like `useAtomValue`, but it doesn't resolve promises: the value of an async atom is returned as a promise, and the component never suspends. It subscribes to the store in an effect, so it doesn't cause an extra re-render on initial mount. As a trade-off, a value change that happens between the initial render and the subscription is not picked up until the next change.

> "Raw" means the promise is returned without being consumed through React's `use()`.

## useAtomValueRawSync

⚠️ This hook is only available since Jotai v3, and it's intended for advanced users.

```jsx
const countAtom = atom(0)

const Counter = () => {
  const count = useAtomValueRawSync(countAtom)
  // ...
}
```

`useAtomValueRawSync` has the same signature as `useAtomValueRaw` and doesn't resolve promises either, but it's implemented with `useSyncExternalStore`. It avoids tearing and picks up values written during mount. As a trade-off, updates are always rendered synchronously without taking advantage of concurrent rendering features.

> "Sync" refers to `useSyncExternalStore`: rendering is always synchronous, with no concurrent-rendering support.

## useSetAtom

```jsx
const switchAtom = atom(false)

const SetTrueButton = () => {
  const setCount = useSetAtom(switchAtom)
  const setTrue = () => setCount(true)

  return (
    <div>
      <button onClick={setTrue}>Set True</button>
    </div>
  )
}

const SetFalseButton = () => {
  const setCount = useSetAtom(switchAtom)
  const setFalse = () => setCount(false)

  return (
    <div>
      <button onClick={setFalse}>Set False</button>
    </div>
  )
}

export default function App() {
  const state = useAtomValue(switchAtom)

  return (
    <div>
      State: <b>{state.toString()}</b>
      <SetTrueButton />
      <SetFalseButton />
    </div>
  )
}
```

In case you need to update a value of an atom without reading it, you can use `useSetAtom()`.

This is especially useful when the performance is a concern, as the `const [, setValue] = useAtom(valueAtom)` will cause unnecessary rerenders on each `valueAtom` update.

---

### Extensions Cache (`docs/extensions/cache.mdx`)

---
title: Cache
description: This doc describes cache extension.
nav: 4.07
keywords: cache
---

Jotai provides primitive functions to optimize re-renders.
It's designed to hold only "current" atom values,
and it doesn't cache older values.

Caching is sometimes useful. For example, if an async atom
triggers network requests, we may want to cache the responses.

[jotai-cache](https://github.com/jotai-labs/jotai-cache) is
a third-party library to help such use cases.

### Install

```
npm install jotai-cache
```

## atomWithCache

```js
atomWithCache(read, options): Atom
```

`atomWithCache` creates a new read-only atom with cache.

### Parameters

**read**: read function to define the read-only atom.

**options** (optional): an object of options to customize the behavior of the atom

### Options

**size** (optional): maximum size of cache items.

**shouldRemove** (optional): a function to check if cache items should be removed.

**areEqual** (optional): a function to compare atom values.

### Examples

```
/* Detailed source-code truncated for AI context efficiency. */
```

### Stackblitz

<Stackblitz id="vitejs-vite-p86ajq" file="src%2FApp.tsx" />

---

### Extensions Effect (`docs/extensions/effect.mdx`)

---
title: Effect
description: A Jōtai utility package for reactive side effects
nav: 4.03
keywords: effect, atom effect, side effect, side-effect, sideeffect
---

[jotai-effect](https://github.com/jotaijs/jotai-effect) is a utility package for reactive side effects in Jotai.

## Install

```
npm install jotai-effect
```

## observe

`observe` mounts an `effect` to watch state changes on a Jotai `store`. It's useful for running global side effects or logic at the store level.

If you don't have access to the store object and are not using the default store, use `atomEffect` or `withAtomEffect` instead.

### Signature

```ts
type Cleanup = () => void

type Effect = (
  get: Getter & { peek: Getter }
  set: Setter & { recurse: Setter }
) => Cleanup | void

type Unobserve = () => void

function observe(effect: Effect, store?: Store): Unobserve
```

**effect:** A function for observing and reacting to atom state changes.

**store:** A Jotai store to mount the effect on. Defaults to the global store if not provided.

**returns:** A stable function that removes the effect from the store and cleans up any internal references.

### Usage

```js
import { observe } from 'jotai-effect'

const unobserve = observe((get, set) => {
  set(logAtom, `someAtom changed: ${get(someAtom)}`)
})

unobserve()
```

This allows you to run Jotai state-dependent logic outside React's lifecycle, ideal for application-wide effects.

### Usage With React

Pass the store to both `observe` and the `Provider` to ensure the effect is mounted to the correct store.

```tsx
const store = createStore()
const unobserve = observe((get, set) => {
  set(logAtom, `someAtom changed: ${get(someAtom)}`)
}, store)

<Provider store={store}>...</Provider>
```

<Stackblitz id="vitejs-vite-uk7p8i5q" file="src%2FApp.tsx" />

## atomEffect

`atomEffect` creates an atom for declaring side effects that react to state changes when mounted.

### Signature

```ts
function atomEffect(effect: Effect): Atom<void>
```

**effect:** A function for observing and reacting to atom state changes.

### Usage

```js
import { atomEffect } from 'jotai-effect'

const logEffect = atomEffect((get, set) => {
  set(logAtom, get(someAtom)) // Runs on mount or when someAtom changes
  return () => {
    set(logAtom, 'unmounting') // Cleanup on unmount
  }
})

// activates the atomEffect while Component is mounted
function Component() {
  useAtom(logEffect)
}
```

## withAtomEffect

`withAtomEffect` binds an effect to a clone of the target atom. The effect is active while the cloned atom is mounted.

### Signature

```ts
function withAtomEffect<T>(targetAtom: Atom<T>, effect: Effect): Atom<T>
```

**targetAtom:** The atom to which the effect is bound.

**effect:** A function for observing and reacting to atom state changes.

**Returns:** An atom that is equivalent to the target atom but having a bound effect.

### Usage

```js
import { withAtomEffect } from 'jotai-effect'

const valuesAtom = withAtomEffect(atom(null), (get, set) => {
  set(valuesAtom, get(countAtom))
  return () => {
    // cleanup
  }
})
```

## Dependency Management

Aside from mount events, the effect runs when any of its dependencies change value.

- **Sync:**
  All atoms accessed with `get` inside the effect are added to the atom's dependencies.

  
  <details style="cursor: pointer; user-select: none;">
    <summary>Example</summary>

  ```js
  atomEffect((get, set) => {
    // updates whenever `anAtom` changes value
    get(anAtom)
  })
  ```

  </details>

- **Async:**
  Asynchronous `get` calls do not add dependencies.

  
  <details style="cursor: pointer; user-select: none;">
    <summary>Example</summary>

  ```js
  atomEffect((get, set) => {
    setTimeout(() => {
      // does not add `anAtom` as a dependency
      get(anAtom)
    })
  })
  ```

  </details>

- **Cleanup:**
  `get` calls in cleanup do not add dependencies.

  
  <details style="cursor: pointer; user-select: none;">
    <summary>Example</summary>

  ```js
  atomEffect((get, set) => {
    return () => {
      // does not add `anAtom` as a dependency
      get(anAtom)
    }
  })
  ```

  </details>

- **Dependency Map Recalculation:**
  Dependencies are recalculated on every run.

  
  <details style="cursor: pointer; user-select: none;">
    <summary>Example</summary>

  ```js
  atomEffect((get, set) => {
    if (get(isEnabledAtom)) {
      // `isEnabledAtom` and `anAtom` are dependencies
      const aValue = get(anAtom)
    } else {
      // `isEnabledAtom` and `anotherAtom` are dependencies
      const anotherValue = get(anotherAtom)
    }
  })
  ```

  </details>

## Effect Behavior

- **Executes Synchronously:**
  `effect` runs synchronous in the current task after synchronous evaluations complete.

  
  <details style="cursor: pointer; user-select: none;">
    <summary>Example</summary>

  ```js
  const logCounts = atomEffect((get, set) => {
    set(logAtom, `count is ${get(countAtom)}`)
  })
  const actionAtom = atom(null, (get, set) => {
    get(logAtom) // 'count is 0'
    set(countAtom, (value) => value + 1)
    get(logAtom) // 'count is 0' - the effect runs once the write function completes
  })
  store.sub(logCounts, () => {})
  store.set(actionAtom)
  store.get(logAtom) // 'count is 1' - the effect ran before `store.set` returned
  ```

  </details>

- **Batched Updates:**
  Multiple synchronous updates are batched as a single atomic transaction.

  
  <details style="cursor: pointer; user-select: none;">
    <summary>Example</summary>

  ```js
  const tensAtom = atom(0)
  const onesAtom = atom(0)
  const updateTensAndOnes = atom(null, (get, set) => {
    set(tensAtom, (value) => value + 1)
    set(onesAtom, (value) => value + 1)
  })
  const combos = atom([])
  const effectAtom = atomEffect((get, set) => {
    const value = get(tensAtom) * 10 + get(onesAtom)
    set(combos, (arr) => [...arr, value])
  })
  store.sub(effectAtom, () => {})
  store.set(updateTensAndOnes)
  store.get(combos) // [00, 11]
  ```

  </details>

- **Resistant to Infinite Loops:**
  `atomEffect` avoids rerunning when it updates a value that it is watching.

  
  <details style="cursor: pointer; user-select: none;">
    <summary>Example</summary>

  ```js
  atomEffect((get, set) => {
    get(countAtom)
    set(countAtom, (value) => value + 1) // Will not loop
  })
  ```

  </details>

- **Cleanup Function:**
  The cleanup function is invoked on unmount or before re-evaluation.

  
  <details style="cursor: pointer; user-select: none;">
    <summary>Example</summary>

  ```js
  atomEffect((get, set) => {
    const intervalId = setInterval(() => set(clockAtom, Date.now()))
    return () => clearInterval(intervalId)
  })
  ```

  </details>

- **Idempotency:**
  `atomEffect` runs once per state change, regardless of how many times it is referenced.

  
  <details style="cursor: pointer; user-select: none;">
    <summary>Example</summary>

  ```js
  let i = 0
  const effectAtom = atomEffect(() => {
    get(countAtom)
    i++
  })
  store.sub(effectAtom, () => {})
  store.sub(effectAtom, () => {})
  store.set(countAtom, (value) => value + 1)
  console.log(i) // 1
  ```

  </details>

- **Conditionally Running Effects:**
  `atomEffect` only runs when mounted.

  
  <details style="cursor: pointer; user-select: none;">
    <summary>Example</summary>

  ```js
  atom((get) => {
    if (get(isEnabledAtom)) {
      get(effectAtom)
    }
  })
  ```

  </details>

- **Supports Peek:**
  Use `get.peek` to read atom data without subscribing.

  
  <details style="cursor: pointer; user-select: none;">
    <summary>Example</summary>

  ```js
  const countAtom = atom(0)
  atomEffect((get, set) => {
    const count = get.peek(countAtom) // Will not add `countAtom` as a dependency
  })
  ```

  </details>

- **Supports Recursion:**
  Recursion is supported with `set.recurse` but not in cleanup.

  
  <details style="cursor: pointer; user-select: none;">
    <summary>Example</summary>

  ```js
  atomEffect((get, set) => {
    const count = get(countAtom)
    if (count % 10 === 0) {
      return
    }
    set.recurse(countAtom, (value) => value + 1)
  })
  ```

  </details>

---

### Extensions Immer (`docs/extensions/immer.mdx`)

---
title: Immer
description: This doc describes Immer extension.
nav: 4.04
keywords: immer
---

### Install

You have to install `immer` and `jotai-immer` to use this feature.

```
npm install immer jotai-immer
```

## atomWithImmer

`atomWithImmer` creates a new atom similar to the regular [`atom`](../core/atom.mdx) with a different `writeFunction`. In this bundle, we don't have read-only atoms, because the point of these functions is the immer produce(mutability) function.
The signature of writeFunction is `(get, set, update: (draft: Draft<Value>) => void) => void`.

```jsx
import { useAtom } from 'jotai'
import { atomWithImmer } from 'jotai-immer'

const countAtom = atomWithImmer({ value: 0 })

const Counter = () => {
  const [count] = useAtom(countAtom)
  return <div>count: {count.value}</div>
}

const Controls = () => {
  const [, setCount] = useAtom(countAtom)
  // setCount === update : (draft: Draft<Value>) => void
  const inc = () =>
    setCount((draft) => {
      ++draft.value
    })
  return <button onClick={inc}>+1</button>
}
```

### Examples

Check this example with atomWithImmer:

<Stackblitz id="vitejs-vite-tblppw" file="src%2FApp.tsx" />

## withImmer

`withImmer` takes an atom and returns a derived atom, same as `atomWithImmer` it has a different `writeFunction`.

```jsx
import { useAtom, atom } from 'jotai'
import { withImmer } from 'jotai-immer'

const primitiveAtom = atom({ value: 0 })
const countAtom = withImmer(primitiveAtom)

const Counter = () => {
  const [count] = useAtom(countAtom)
  return <div>count: {count.value}</div>
}

const Controls = () => {
  const [, setCount] = useAtom(countAtom)
  // setCount === update : (draft: Draft<Value>) => void
  const inc = () =>
    setCount((draft) => {
      ++draft.value
    })
  return <button onClick={inc}>+1</button>
}
```

### Examples

Check this example with withImmer:

<Stackblitz id="vitejs-vite-jwfjqm" file="src%2FApp.tsx" />

## useImmerAtom

This hook takes an atom and replaces the atom's `writeFunction` with the new immer-like `writeFunction` like the previous helpers.

```jsx
import { atom } from 'jotai'
import { useImmerAtom } from 'jotai-immer'

const primitiveAtom = atom({ value: 0 })

const Counter = () => {
  const [count] = useImmerAtom(primitiveAtom)
  return <div>count: {count.value}</div>
}

const Controls = () => {
  const [, setCount] = useImmerAtom(primitiveAtom)
  // setCount === update : (draft: Draft<Value>) => void
  const inc = () =>
    setCount((draft) => {
      ++draft.value
    })
  return <button onClick={inc}>+1</button>
}
```

It would be better if you don't use `withImmer` and `atomWithImmer` with `useImmerAtom` because they provide the immer-like `writeFunction` and we don't need to create a new one.

You can use `useSetImmerAtom` if you need only the setter part of `useImmerAtom`.

### Examples

Check this example with useImmerAtom:

<Stackblitz id="vitejs-vite-k2rixl" file="src%2FApp.tsx" />

## Demo

<Stackblitz id="vitejs-vite-tksbwq" file="src%2FApp.tsx" />

---

### Extensions Location (`docs/extensions/location.mdx`)

---
title: Location
description: This doc describes window.location extension.
nav: 4.06
keywords: location,hash
---

To deal with `window.location`, we have some functions to create atoms.

### Install

You have to install `jotai-location` to use this feature.

```
npm install jotai-location
```

## atomWithLocation

```js
atomWithLocation(options): PrimitiveAtom
```

`atomWithLocation` creates a new atom that links to `window.location`.

Typically, you should only instantiate `atomWithLocation` once per application. This is because changes made to one instance might not be reflected in others.
As this atom is designed to synchronize with the `window.location` object, using multiple instances can lead to unpredictable behavior.

### Parameters

**options** (optional): an object of options to customize the behavior of the atom

### Options

**preloaded** (optional): preloaded location value to avoid getting location at initialization.

**replace** (optional): a boolean to indicate to use `replaceState` instead of `pushState`.

**getLocation** (optional): a custom function to get location value.

**applyLocation** (optional): a custom function to set location value.

**subscribe** (optional): a custom function to subscribe to location change.

### Examples

```jsx
import { useAtom } from 'jotai'
import { atomWithLocation } from 'jotai-location'

const locationAtom = atomWithLocation()

const App = () => {
  const [loc, setLoc] = useAtom(locationAtom)
  return (
    <ul>
      <li>
        <button
          style={{
            fontWeight: loc.pathname === '/' ? 'bold' : 'normal',
          }}
          onClick={() => setLoc((prev) => ({ ...prev, pathname: '/' }))}
        >
          Home
        </button>
      </li>
      <li>
        <button
          style={{
            fontWeight:
              loc.pathname === '/foo' && !loc.searchParams?.get('bar')
                ? 'bold'
                : 'normal',
          }}
          onClick={() =>
            setLoc((prev) => ({
              ...prev,
              pathname: '/foo',
              searchParams: new URLSearchParams(),
            }))
          }
        >
          Foo
        </button>
      </li>
      <li>
        <button
          style={{
            fontWeight:
              loc.pathname === '/foo' && loc.searchParams?.get('bar') === '1'
                ? 'bold'
                : 'normal',
          }}
          onClick={() =>
            setLoc((prev) => ({
              ...prev,
              pathname: '/foo',
              searchParams: new URLSearchParams([['bar', '1']]),
            }))
          }
        >
          Foo?bar=1
        </button>
      </li>
    </ul>
  )
}
```

### Stackblitz

<Stackblitz id="vitejs-vite-9v72fq" file="src%2FApp.tsx" />

## atomWithHash

```js
atomWithHash(key, initialValue, options): PrimitiveAtom
```

This creates a new atom that is connected with URL hash.
The hash must be in the URLSearchParams format.
It's a two-way binding: changing the atom value will change the hash and
changing the hash will change the atom value.
This function works only with DOM.

### Parameters

**key** (required): a unique string used as the key when syncing state with localStorage, sessionStorage, or AsyncStorage

**initialValue** (required): the initial value of the atom

**options** (optional): an object of options to customize the behavior of the atom

### Options

**serialize** (optional): a custom function to serialize the atom value to the hash. Defaults to `JSON.stringify`.

**deserialize** (optional): a custom function to deserialize the hash to the atom value. Defaults to `JSON.parse`.

**subscribe** (optional): custom hash change subscribe function

**setHash** (optional): `replaceState` or a custom function that describes how hash gets updated on the side of the browser. Defaults to pushing a new entry to the history via `window.location.hash = searchParams` ([jotai-location#4](https://github.com/jotaijs/jotai-location/pull/4))

### Examples

```jsx
import { useAtom } from 'jotai'
import { atomWithHash } from 'jotai-location'

const countAtom = atomWithHash('count', 1)

const Counter = () => {
  const [count, setCount] = useAtom(countAtom)
  return (
    <div>
      <div>count: {count}</div>
      <button onClick={() => setCount((c) => c + 1)}>+1</button>
    </div>
  )
}
```

### Stackblitz

<Stackblitz id="vitejs-vite-zngpjt" file="src%2FApp.tsx" />

### Deleting Item

Please refer [atomWithStorage](../utilities/storage.mdx)
for the usage about deleting items.

---

### Extensions Optics (`docs/extensions/optics.mdx`)

---
title: Optics
description: This doc describes Optics-ts extension.
nav: 4.09
keywords: optics
---

### Install

You have to install `optics-ts` and `jotai-optics` to use this feature.

```
npm install optics-ts jotai-optics
```

## focusAtom

`focusAtom` creates a new atom, based on the focus that you pass to it. This creates a derived atom that will focus on the specified part of the atom,
and when the derived atom is updated, the derivee is notified of the update, and the equivalent update is done on the derivee.

See this:

```js
const baseAtom = atom({ a: 5 }) // PrimitiveAtom<{a: number}>
const derivedAtom = focusAtom(baseAtom, (optic) => optic.prop('a')) // PrimitiveAtom<number>
```

So basically, we started with a `PrimitiveAtom<{a: number}>`, which has a getter and a setter, and then used `focusAtom` to zoom in on the `a`-property of
the `baseAtom`, and got a `PrimitiveAtom<number>`. What is noteworthy here is that this `derivedAtom` is not only a getter, it is also a setter. If `derivedAtom` is updated, then equivalent update is done on the `baseAtom`.

The example below is simple, but it's a starting point. `focusAtom` supports many kinds of optics, including `Lens`, `Prism`, `Isomorphism`.

To see more advanced optics, please see the example at: https://github.com/akheron/optics-ts

### Example

```jsx
import { atom } from 'jotai'
import { focusAtom } from 'jotai-optics'

const objectAtom = atom({ a: 5, b: 10 })
const aAtom = focusAtom(objectAtom, (optic) => optic.prop('a'))
const bAtom = focusAtom(objectAtom, (optic) => optic.prop('b'))

const Controls = () => {
  const [a, setA] = useAtom(aAtom)
  const [b, setB] = useAtom(bAtom)
  return (
    <div>
      <span>Value of a: {a}</span>
      <span>Value of b: {b}</span>
      <button onClick={() => setA((oldA) => oldA + 1)}>Increment a</button>
      <button onClick={() => setB((oldB) => oldB + 1)}>Increment b</button>
    </div>
  )
}
```

#### Stackblitz

<Stackblitz id="vitejs-vite-jjunki" file="src%2FApp.tsx" />

---

### Extensions Query (`docs/extensions/query.mdx`)

---
title: Query
description: This doc describes TanStack Query extension.
nav: 4.02
keywords: tanstack,query
---

[TanStack Query](https://tanstack.com/query/) provides a set of functions for managing async state (typically external data).

From the [Overview docs](https://tanstack.com/query/v5/docs/framework/react/overview):

> React Query is often described as the missing data-fetching library for React, but in more technical terms, it makes **fetching, caching, synchronizing and updating server state** in your React applications a breeze.

[jotai-tanstack-query](https://github.com/jotai-labs/jotai-tanstack-query) is a Jotai extension library for TanStack Query. It provides a wonderful interface with all of the TanStack Query features, providing you the ability to use those features in combination with your existing Jotai state.

### Support

jotai-tanstack-query currently supports TanStack Query v5.

### Install

In addition to `jotai`, you have to install `jotai-tanstack-query` and `@tanstack/query-core` to use the extension.

```bash
npm install jotai-tanstack-query @tanstack/query-core
```

### Incremental Adoption

You can incrementally adopt `jotai-tanstack-query` in your app. It's not an all or nothing solution. You just have to ensure you are using the same QueryClient instance. [QueryClient Setup](#referencing-the-same-instance-of-query-client-in-your-project).

```jsx
// existing useQueryHook
const { data, isPending, isError } = useQuery({
  queryKey: ['todos'],
  queryFn: fetchTodoList,
})

// jotai-tanstack-query
const todosAtom = atomWithQuery(() => ({
  queryKey: ['todos'],
}))

const [{ data, isPending, isError }] = useAtom(todosAtom)
```

### Exported functions

- `atomWithQuery` for [useQuery](https://tanstack.com/query/v5/docs/react/reference/useQuery)
- `atomWithInfiniteQuery` for [useInfiniteQuery](https://tanstack.com/query/v5/docs/react/reference/useInfiniteQuery)
- `atomWithMutation` for [useMutation](https://tanstack.com/query/v5/docs/react/reference/useMutation)
- `atomWithSuspenseQuery` for [useSuspenseQuery](https://tanstack.com/query/v5/docs/react/reference/useSuspenseQuery)
- `atomWithSuspenseInfiniteQuery` for [useSuspenseInfiniteQuery](https://tanstack.com/query/v5/docs/react/reference/useSuspenseInfiniteQuery)
- `atomWithMutationState` for [useMutationState](https://tanstack.com/query/v5/docs/react/reference/useMutationState)

All functions follow the same signature.

```ts
const dataAtom = atomWithSomething(getOptions, getQueryClient)
```

The first `getOptions` parameter is a function that returns an input to the observer.
The second optional `getQueryClient` parameter is a function that return [QueryClient](https://tanstack.com/query/v5/docs/reference/QueryClient).

### atomWithQuery usage

`atomWithQuery` creates a new atom that implements a standard [`Query`](https://tanstack.com/query/v5/docs/react/guides/queries) from TanStack Query.

```jsx
import { atom, useAtom } from 'jotai'
import { atomWithQuery } from 'jotai-tanstack-query'

const idAtom = atom(1)
const userAtom = atomWithQuery((get) => ({
  queryKey: ['users', get(idAtom)],
  queryFn: async ({ queryKey: [, id] }) => {
    const res = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`)
    return res.json()
  },
}))

const UserData = () => {
  const [{ data, isPending, isError }] = useAtom(userAtom)

  if (isPending) return <div>Loading...</div>
  if (isError) return <div>Error</div>

  return <div>{JSON.stringify(data)}</div>
}
```

### atomWithInfiniteQuery usage

`atomWithInfiniteQuery` is very similar to `atomWithQuery`, however it is for an `InfiniteQuery`, which is used for data that is meant to be paginated. You can [read more about Infinite Queries here](https://tanstack.com/query/v5/docs/framework/react/guides/infinite-queries).

> Rendering lists that can additively "load more" data onto an existing set of data or "infinite scroll" is also a very common UI pattern. React Query supports a useful version of useQuery called useInfiniteQuery for querying these types of lists.

A notable difference between a standard query atom is the additional option `getNextPageParam` and `getPreviousPageParam`, which is what you'll use to instruct the query on how to fetch any additional pages.

```jsx
import { atom, useAtom } from 'jotai'
import { atomWithInfiniteQuery } from 'jotai-tanstack-query'

const postsAtom = atomWithInfiniteQuery(() => ({
  queryKey: ['posts'],
  queryFn: async ({ pageParam }) => {
    const res = await fetch(`https://jsonplaceholder.typicode.com/posts?_page=${pageParam}`)
    return res.json()
  },
  getNextPageParam: (lastPage, allPages, lastPageParam) => lastPageParam + 1,
  initialPageParam: 1,
}))

const Posts = () => {
  const [{ data, fetchNextPage, isPending, isError, isFetching }] =
    useAtom(postsAtom)

  if (isPending) return <div>Loading...</div>
  if (isError) return <div>Error</div>

  return (
    <>
      {data.pages.map((page, index) => (
        <div key={index}>
          {page.map((post: any) => (
            <div key={post.id}>{post.title}</div>
          ))}
        </div>
      ))}
      <button onClick={() => fetchNextPage()}>Next</button>
    </>
  )
}
```

### atomWithMutation usage

`atomWithMutation` creates a new atom that implements a standard [`Mutation`](https://tanstack.com/query/v5/docs/framework/react/guides/mutations) from TanStack Query.

> Unlike queries, mutations are typically used to create/update/delete data or perform server side-effects.

```tsx
const postAtom = atomWithMutation(() => ({
  mutationKey: ['posts'],
  mutationFn: async ({ title }: { title: string }) => {
    const res = await fetch(`https://jsonplaceholder.typicode.com/posts`, {
      method: 'POST',
      body: JSON.stringify({
        title,
        body: 'body',
        userId: 1,
      }),
      headers: {
        'Content-type': 'application/json; charset=UTF-8',
      },
    })
    const data = await res.json()
    return data
  },
}))

const Posts = () => {
  const [{ mutate, status }] = useAtom(postAtom)
  return (
    <div>
      <button onClick={() => mutate({ title: 'foo' })}>Click me</button>
      <pre>{JSON.stringify(status, null, 2)}</pre>
    </div>
  )
}
```

### atomWithMutationState usage

`atomWithMutationState` creates a new atom that gives you access to all mutations in the [`MutationCache`](https://tanstack.com/query/v5/docs/react/reference/useMutationState).

```jsx
const mutationStateAtom = atomWithMutationState((get) => ({
  filters: {
    mutationKey: ['posts'],
  },
}))
```

### Suspense

jotai-tanstack-query can also be used with React's Suspense.

### atomWithSuspenseQuery usage

```jsx
import { atom, useAtom } from 'jotai'
import { atomWithSuspenseQuery } from 'jotai-tanstack-query'

const idAtom = atom(1)
const userAtom = atomWithSuspenseQuery((get) => ({
  queryKey: ['users', get(idAtom)],
  queryFn: async ({ queryKey: [, id] }) => {
    const res = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`)
    return res.json()
  },
}))

const UserData = () => {
  const [{ data }] = useAtom(userAtom)

  return <div>{JSON.stringify(data)}</div>
}
```

### atomWithSuspenseInfiniteQuery usage

```jsx
import { atom, useAtom } from 'jotai'
import { atomWithSuspenseInfiniteQuery } from 'jotai-tanstack-query'

const postsAtom = atomWithSuspenseInfiniteQuery(() => ({
  queryKey: ['posts'],
  queryFn: async ({ pageParam }) => {
    const res = await fetch(`https://jsonplaceholder.typicode.com/posts?_page=${pageParam}`)
    return res.json()
  },
  getNextPageParam: (lastPage, allPages, lastPageParam) => lastPageParam + 1,
  initialPageParam: 1,
}))

const Posts = () => {
  const [{ data, fetchNextPage, isPending, isError, isFetching }] =
    useAtom(postsAtom)

  return (
    <>
      {data.pages.map((page, index) => (
        <div key={index}>
          {page.map((post: any) => (
            <div key={post.id}>{post.title}</div>
          ))}
        </div>
      ))}
      <button onClick={() => fetchNextPage()}>Next</button>
    </>
  )
}
```

### Referencing the same instance of Query Client in your project

Perhaps you have some custom hooks in your project that utilises the `useQueryClient()` hook to obtain the `QueryClient` object and call its methods.

To ensure that you reference the same `QueryClient` object, be sure to wrap the root of your project in a `<Provider>` and initialise `queryClientAtom` with the same `queryClient` value you provided to `QueryClientProvider`.

Without this step, `useQueryAtom` will reference a separate `QueryClient` from any hooks that utilise the `useQueryClient()` hook to get the queryClient.

Alternatively, you can specify your `queryClient` with `getQueryClient` parameter.

#### Example

In the example below, we have a mutation hook, `useTodoMutation` and a query `todosAtom`.

We included an initialisation step in our root `<App>` node.

Although they reference methods same query key (`'todos'`), the `onSuccess` invalidation in `useTodoMutation` will not trigger **if the `Provider` initialisation step was not done.**

This will result in `todosAtom` showing stale data as it was not prompted to refetch.

⚠️ Note: When using **Typescript**, it is recommended to use a Map when passing the queryClient value to useHydrateAtoms. You can find a working example in the [Initializing State on Render docs](https://jotai.org/docs/guides/initialize-atom-on-render#using-typescript)

```jsx
import { Provider } from 'jotai/react'
import { useHydrateAtoms } from 'jotai/react/utils'
import {
  useMutation,
  useQueryClient,
  QueryClient,
  QueryClientProvider,
} from '@tanstack/react-query'
import { atomWithQuery, queryClientAtom } from 'jotai-tanstack-query'

const queryClient = new QueryClient()

const HydrateAtoms = ({ children }) => {
  useHydrateAtoms([[queryClientAtom, queryClient]])
  return children
}

export const App = () => {
  return (
    <QueryClientProvider client={queryClient}>
      <Provider>
        {/*
   This Provider initialisation step is needed so that we reference the same
   queryClient in both atomWithQuery and other parts of the app. Without this,
   our useQueryClient() hook will return a different QueryClient object
	*/}
        <HydrateAtoms>
          <App />
        </HydrateAtoms>
      </Provider>
    </QueryClientProvider>
  )
}

export const todosAtom = atomWithQuery((get) => {
  return {
    queryKey: ['todos'],
    queryFn: () => fetch('/todos'),
  }
})

export const useTodoMutation = () => {
  const queryClient = useQueryClient()

  return useMutation(
    async (body: todo) => {
      await fetch('/todo', { Method: 'POST', Body: body })
    },
    {
      onSuccess: () => {
        void queryClient.invalidateQueries(['todos'])
      },
      onError,
    }
  )
}
```

### SSR support

All atoms can be used within the context of a server side rendered app, such as a next.js app or Gatsby app. You can [use both options](https://tanstack.com/query/v5/docs/framework/react/guides/ssr) that React Query supports for use within SSR apps, [hydration](https://tanstack.com/query/v5/docs/react/guides/ssr#using-the-hydration-apis) or [`initialData`](https://tanstack.com/query/v5/docs/react/guides/ssr#get-started-fast-with-initialdata).

### Error handling

Fetch error will be thrown and can be caught with ErrorBoundary.
Refetching may recover from a temporary error.

See [a working example](https://codesandbox.io/s/4gfp6z) to learn more.

### Devtools

In order to use the Devtools, you need to install it additionally.

```bash
npm install @tanstack/react-query-devtools
```

All you have to do is put the `<ReactQueryDevtools />` within `<QueryClientProvider />`.

```tsx
import {
  QueryClientProvider,
  QueryClient,
  QueryCache,
} from '@tanstack/react-query'
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
import { queryClientAtom } from 'jotai-tanstack-query'

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      staleTime: Infinity,
    },
  },
})

const HydrateAtoms = ({ children }) => {
  useHydrateAtoms([[queryClientAtom, queryClient]])
  return children
}

export const App = () => {
  return (
    <QueryClientProvider client={queryClient}>
      <Provider>
        <HydrateAtoms>
          <App />
        </HydrateAtoms>
      </Provider>
      <ReactQueryDevtools />
    </QueryClientProvider>
  )
}
```

## Migrate to v0.8.0

### Change in atom signature

All atom signatures have changed to be more consistent with TanStack Query.
v0.8.0 returns only a single atom, instead of a tuple of atoms, and hence the name change from `atomsWithSomething` to`atomWithSomething`.

```diff

- const [dataAtom, statusAtom] = atomsWithSomething(getOptions, getQueryClient)
+ const dataAtom = atomWithSomething(getOptions, getQueryClient)

```

### Simplified Return Structure

In the previous version of `jotai-tanstack-query`, the query atoms `atomsWithQuery` and `atomsWithInfiniteQuery` returned a tuple of atoms: `[dataAtom, statusAtom]`. This design separated the data and its status into two different atoms.

#### atomWithQuery and atomWithInfiniteQuery

- `dataAtom` was used to access the actual data (`TData`).
- `statusAtom` provided the status object (`QueryObserverResult<TData, TError>`), which included additional attributes like `isPending`, `isError`, etc.

In v0.8.0, they have been replaced by `atomWithQuery` and `atomWithInfiniteQuery` to return only a single `dataAtom`. This `dataAtom` now directly provides the `QueryObserverResult<TData, TError>`, aligning it closely with the behavior of Tanstack Query's bindings.

To migrate to the new version, replace the separate `dataAtom` and `statusAtom` usage with the unified `dataAtom` that now contains both data and status information.

```diff
- const [dataAtom, statusAtom] = atomsWithQuery(/* ... */);
- const [data] = useAtom(dataAtom);
- const [status] = useAtom(statusAtom);

+ const dataAtom = atomWithQuery(/* ... */);
+ const [{ data, isPending, isError }] = useAtom(dataAtom);
```

#### atomWithMutation

Similar to `atomsWithQuery` and `atomsWithInfiniteQuery`, `atomWithMutation` also returns a single atom instead of a tuple of atoms. The return type of the atom value is `MutationObserverResult<TData, TError, TVariables, TContext>`.

```diff

- const [, postAtom] = atomsWithMutation(/* ... */);
- const [post, mutate] = useAtom(postAtom); // Accessing mutation status from post; and mutate() to execute the mutation

+ const postAtom = atomWithMutation(/* ... */);
+ const [{ data, error, mutate }] = useAtom(postAtom); // Accessing mutation result and mutate method from the same atom

```

### Examples

#### Basic demo

<Stackblitz id="vitejs-vite-pr9eaf" file="src%2FApp.tsx" />

#### Devtools demo

<Stackblitz id="vitejs-vite-btdqkh" file="src%2FApp.tsx" />

#### Hackernews

<Stackblitz id="vitejs-vite-wqsyj8" file="src%2FApp.tsx" />

---

### Extensions Redux (`docs/extensions/redux.mdx`)

---
title: Redux
description: This doc describes Redux extension.
nav: 4.98
keywords: redux
published: false
---

Jotai's state resides in React, but sometimes it would be nice
to interact with the world outside React.

Redux provides a store interface that can be used to store some values
and sync with atoms in Jotai.

### Install

You have to install `redux` and `jotai-redux` to use this feature.

```
npm install redux jotai-redux
```

## atomWithStore

`atomWithStore` creates a new atom with redux store.
It's two-way binding and you can change the value from both ends.

```jsx
import { useAtom } from 'jotai'
import { atomWithStore } from 'jotai-redux'
import { createStore } from 'redux'

const initialState = { count: 0 }
const reducer = (state = initialState, action: { type: 'INC' }) => {
  if (action.type === 'INC') {
    return { ...state, count: state.count + 1 }
  }
  return state
}
const store = createStore(reducer)
const storeAtom = atomWithStore(store)

const Counter = () => {
  const [state, dispatch] = useAtom(storeAtom)

  return (
    <>
      count: {state.count}
      <button onClick={() => dispatch({ type: 'INC' })}>button</button>
    </>
  )
}
```

### Examples

<Stackblitz id="vitejs-vite-qqsnwc" file="src%2FApp.tsx" />

---

### Extensions Relay (`docs/extensions/relay.mdx`)

---
title: Relay
description: This doc describes Relay extension.
nav: 4.98
keywords: relay
published: false
---

You can use Jotai with [Relay](https://relay.dev).

### Install

You have to install `jotai-relay` and `relay-runtime`.

```
npm install jotai-relay relay-runtime
```

### Usage

See [Relay Docs](https://relay.dev/docs/) to
learn about basics and how to use compiler in advance.

### atomWithQuery

`atomWithQuery` creates a new atom with [fetchQuery](https://relay.dev/docs/api-reference/fetch-query/).

```jsx
import React, { Suspense } from 'react'
import { Provider, useAtom } from 'jotai'
import { useHydrateAtoms } from 'jotai/utils'
import { environmentAtom, atomWithQuery } from 'jotai-relay'
import { Environment, Network, RecordSource, Store } from 'relay-runtime'
import graphql from 'babel-plugin-relay/macro'

const myEnvironment = new Environment({
  network: Network.create(async (params, variables) => {
    const response = await fetch('https://countries.trevorblades.com/', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        query: params.text,
        variables,
      }),
    })
    return response.json()
  }),
  store: new Store(new RecordSource()),
})

const countriesAtom = atomWithQuery(
  graphql`
    query AppCountriesQuery {
      countries {
        name
      }
    }
  `,
  () => ({}),
)

const Main = () => {
  const [data] = useAtom(countriesAtom)
  return (
    <ul>
      {data.countries.map(({ name }) => (
        <li key={name}>{name}</li>
      ))}
    </ul>
  )
}

const HydrateAtoms = ({ children }) => {
  useHydrateAtoms([[environmentAtom, myEnvironment]])
  return children
}

const App = () => {
  return (
    <Provider>
      <HydrateAtoms>
        <Suspense fallback="Loading...">
          <Main />
        </Suspense>
      </HydrateAtoms>
    </Provider>
  )
}
```

#### Examples

<Stackblitz id="vitejs-vite-divyhe" file="src%2FApp.tsx" />

### atomWithMutation

`atomWithMutation` creates a new atom with [commitMutation](https://relay.dev/docs/api-reference/commit-mutation/).

FIXME: add code example and codesandbox

### atomWithSubscription

`atomWithSubscription` creates a new atom with [requestSubscription](https://relay.dev/docs/api-reference/request-subscription/).

FIXME: add code example and codesandbox

---

### Extensions Scope (`docs/extensions/scope.mdx`)

---
title: Scope
description: This doc describes scope extension.
nav: 4.08
keywords: scope
---

There are a few libraries to extend Jotai's usage in React.

## `jotai-scope`

While Jotai's Provider allows to scope Jotai's store under a subtree,
we can't use the store above the tree within the subtree.

A workaround is to use `store` option in useAtom and other hooks.

Instead of specifying the `store` option,
`<ScopeProvider>` lets you reuse the _same_ atoms in different parts
of the React tree **without sharing state** while still being able to
read other atoms from the parent store.

### Install

```
npm install jotai-scope
```

### Counter Example

```tsx
import { atom, useAtom } from 'jotai'
import { ScopeProvider } from 'jotai-scope'

const countAtom = atom(0)

function Counter() {
  const [count, setCount] = useAtom(countAtom)
  const [anotherCount, setAnotherCount] = useAtom(anotherCountAtom)
  return (
    <>
      <div>
        <span>count: {count}</span>
        <button type="button" onClick={() => setCount((v) => v + 1)}>
          increment
        </button>
      </div>
      <div>
        <span>another count: {anotherCount}</span>
        <button type="button" onClick={() => setAnotherCount((v) => v + 1)}>
          increment
        </button>
      </div>
    </>
  )
}

function App() {
  return (
    <div>
      <Counter />
      <ScopeProvider atoms={[countAtom]}>
        <Counter />
      </ScopeProvider>
    </div>
  )
}
```

<Stackblitz id="vitejs-vite-ctcuhj" file="src%2FApp.tsx" />

## `createIsolation`

Both Jotai's Provider and `jotai-scope`'s scoped provider
are still using global contexts.

If you are developing a library that depends on Jotai and
the library user may use Jotai separately in their apps,
they can share the same context. This can be troublesome
because they point to unexpected Jotai stores.

To avoid conflicting the contexts,
a utility function called `createIsolation` is exported from `jotai-scope`.

```tsx
import { createIsolation } from 'jotai-scope'

const { Provider, useStore, useAtom, useAtomValue, useSetAtom } =
  createIsolation()

function Library() {
  return (
    <Provider>
      <LibraryComponent />
    </Provider>
  )
}
```

## `bunshi` (formerly `jotai-molecules`)

Jotai atoms provide a basic solution to optimize re-renders.
Atoms defined globally can depend on other atoms,
but they can't depend on props and state within a component tree.
It's possible to define atoms within a component tree,
but then you would need to pass those atoms in some ways
(for example, [atoms-in-atom](../guides/atoms-in-atom.mdx).)

[bunshi](https://github.com/saasquatch/bunshi) is
a third-party library to help such use cases.

See [Motivation](https://github.com/saasquatch/bunshi/tree/v1.1.1#motivation) for more details.

### Install

```
npm install bunshi
```

### Counter Example

```jsx
import { atom, useAtom } from 'jotai'
import { molecule, useMolecule, createScope, ScopeProvider } from 'bunshi/react'

const InitialCountScope = createScope({ initialCount: 0 })
const countMolecule = molecule((getMol, getScope) => {
  const { initialCount } = getScope(InitialCountScope)
  return atom(initialCount)
})

function Counter() {
  const countAtom = useMolecule(countMolecule)
  const [count, setCount] = useAtom(countAtom)
  return (
    <div>
      {count} <button onClick={() => setCount((v) => v + 1)}>+1</button>
    </div>
  )
}

function App() {
  return (
    <div>
      <h1>With initial value 1</h1>
      <ScopeProvider scope={InitialCountScope} value={{ initialCount: 1 }}>
        <Counter />
        <Counter />
      </ScopeProvider>
      <h1>With initial value 2</h1>
      <ScopeProvider scope={InitialCountScope} value={{ initialCount: 2 }}>
        <Counter />
        <Counter />
      </ScopeProvider>
      <h1>Default</h1>
      <Counter />
      <Counter />
    </div>
  )
}
```

<Stackblitz id="vitejs-vite-8akpt6" file="src%2FApp.tsx" />

---

### Extensions Trpc (`docs/extensions/trpc.mdx`)

---
title: tRPC
description: This doc describes tRPC extension.
nav: 4.01
keywords: rpc,trpc,typescript,t3
---

You can use Jotai with [tRPC](https://trpc.io).

### Install

You have to install `jotai-trpc`, `@trpc/client` and `@trpc/server` to use the extension.

```
npm install jotai-trpc @trpc/client @trpc/server
```

### Usage

```ts
import { createTRPCJotai } from 'jotai-trpc'

const trpc = createTRPCJotai<MyRouter>({
  links: [
    httpLink({
      url: myUrl,
    }),
  ],
})

const idAtom = atom('foo')
const queryAtom = trpc.bar.baz.atomWithQuery((get) => get(idAtom))
```

### atomWithQuery

`...atomWithQuery` creates a new atom with "query". It internally uses [Vanilla Client](https://trpc.io/docs/vanilla)'s `...query` procedure.

```tsx
import { atom, useAtom } from 'jotai'
import { httpLink } from '@trpc/client'
import { createTRPCJotai } from 'jotai-trpc'
import { trpcPokemonUrl } from 'trpc-pokemon'
import type { PokemonRouter } from 'trpc-pokemon'

const trpc = createTRPCJotai<PokemonRouter>({
  links: [
    httpLink({
      url: trpcPokemonUrl,
    }),
  ],
})

const NAMES = [
  'bulbasaur',
  'ivysaur',
  'venusaur',
  'charmander',
  'charmeleon',
  'charizard',
  'squirtle',
  'wartortle',
  'blastoise',
]

const nameAtom = atom(NAMES[0])

const pokemonAtom = trpc.pokemon.byId.atomWithQuery((get) => get(nameAtom))

const Pokemon = () => {
  const [data, refresh] = useAtom(pokemonAtom)
  return (
    <div>
      <div>ID: {data.id}</div>
      <div>Height: {data.height}</div>
      <div>Weight: {data.weight}</div>
      <button onClick={refresh}>Refresh</button>
    </div>
  )
}
```

#### Examples

<Stackblitz id="vitejs-vite-8kgfpj" file="src%2FApp.tsx" />

### atomWithMutation

`...atomWithMutation` creates a new atom with "mutate". It internally uses [Vanilla Client](https://trpc.io/docs/vanilla)'s `...mutate` procedure.

FIXME: add code example and codesandbox

### atomWithSubscription

`...atomWithSubscription` creates a new atom with "subscribe". It internally uses [Vanilla Client](https://trpc.io/docs/vanilla)'s `...subscribe` procedure.

FIXME: add code example and codesandbox

---

### Extensions Urql (`docs/extensions/urql.mdx`)

---
title: URQL
description: This doc describes URQL extension.
nav: 4.03
keywords: urql
---

[urql](https://formidable.com/open-source/urql/) offers a toolkit for GraphQL querying, caching, and state management.

From the [Overview docs](https://formidable.com/open-source/urql/docs/):

> urql is a highly customizable and versatile GraphQL client with which you add on features like normalized caching as you grow. It's built to be both easy to use for newcomers to GraphQL, and extensible, to grow to support dynamic single-app applications and highly customized GraphQL infrastructure. In short, urql prioritizes usability and adaptability.

[jotai-urql](https://github.com/jotaijs/jotai-urql) is a Jotai extension library for URQL. It offers a cohesive interface that incorporates all of URQL's GraphQL features, allowing you to leverage these functionalities alongside your existing Jotai state.

### Install

You have to install `jotai-urql`, `@urql/core` and `wonka` to use the extension.

```
npm install jotai-urql @urql/core wonka
```

### Exported functions

- `atomWithQuery` for [client.query](https://formidable.com/open-source/urql/docs/api/core/#clientquery)
- `atomWithMutation` for [client.mutation](https://formidable.com/open-source/urql/docs/api/core/#clientmutation)
- `atomWithSubscription` for [client.subscription](https://formidable.com/open-source/urql/docs/api/core/#clientsubscription)

### Basic usage

#### Query:

```tsx
import { useAtom } from 'jotai'

const countQueryAtom = atomWithQuery<{ count: number }>({
  query: 'query Count { count }',
  getClient: () => client, // This option is optional if `useRehydrateAtom([[clientAtom, client]])` is used globally
})

const Counter = () => {
  // Will suspend until first operation result is resolved. Either with error, partial data, data
  const [operationResult, reexecute] = useAtom(countQueryAtom)

  if (operationResult.error) {
    // This shall be handled in the parent ErrorBoundary above
    throw operationResult.error
  }

  // You have to use optional chaining here, as data may be undefined at this point (only in case of error)
  return <>{operationResult.data?.count}</>
}
```

#### Mutation:

```tsx
import { useAtom } from 'jotai'

const incrementMutationAtom = atomWithMutation<{ increment: number }>({
  query: 'mutation Increment { increment }',
})

const Counter = () => {
  const [operationResult, executeMutation] = useAtom(incrementMutationAtom)
  return (
    <div>
      <button
        onClick={() =>
          executeMutation().then((it) => console.log(it.data?.increment))
        }
      >
        Increment
      </button>
      <div>{operationResult.data?.increment}</div>
    </div>
  )
}
```

### Simplified type of options passed to functions

```tsx
type AtomWithQueryOptions<
  Data = unknown,
  Variables extends AnyVariables = AnyVariables,
> = {
  // Supports string query, typed-document-node, document node etc.
  query: DocumentInput<Data, Variables>
  // Will be enforced dynamically based on generic/typed-document-node types.
  getVariables?: (get: Getter) => Variables
  getContext?: (get: Getter) => Partial<OperationContext>
  getPause?: (get: Getter) => boolean
  getClient?: (get: Getter) => Client
}

type AtomWithMutationOptions<
  Data = unknown,
  Variables extends AnyVariables = AnyVariables,
> = {
  query: DocumentInput<Data, Variables>
  getClient?: (get: Getter) => Client
}

// Subscription type is the same as AtomWithQueryOptions
```

### Disable suspense

Usage of `import { loadable } from "jotai/utils"` is preferred instead as proven more stable. However is you still want that
here is how you do it:

```tsx
import { suspenseAtom } from 'jotai-urql'

export const App = () => {
  // We disable suspense for the entire app
  useHydrateAtoms([[suspenseAtom, false]])
  return <Counter />
}
```

### Useful helper hook

Here is the helper hook, to cover one rare corner case, and make use of these bindings similar to `@tanstack/react-query`
default behavior where errors are treated as errors (in case of Promise reject) and are handled mostly in the nearby
ErrorBoundaries. Only valid for suspended version.

#### useQueryAtomData

Neatly returns `data` after the resolution + handles all the error throwing/reexecute cases/corner cases.
Note that Type is overridden so `data` it never `undefined` nor `null` (unless that's expected return type of the query itself)

```
/* Detailed source-code truncated for AI context efficiency. */
```

#### Basic demo

<Stackblitz id="vitejs-vite-1nhtrj" file="src%2FApp.tsx" />

### Referencing the same instance of the client for both atoms and urql provider

To ensure that you reference the same urqlClient object, be sure to wrap the root of your project in a `<Provider>` and initialise clientAtom with the same urqlClient value you provided to UrqlProvider.

Without this step, you may end up specifying client each time when you use `atomWithQuery`. Now you can just ignore the optional `getClient` parameter, and it will use the client from the context.

```jsx
import { Suspense } from 'react'
import { Provider } from 'jotai/react'
import { useHydrateAtoms } from 'jotai/react/utils'
import { clientAtom } from 'jotai-urql'

import {
  createClient,
  cacheExchange,
  fetchExchange,
  Provider as UrqlProvider,
} from 'urql'

const urqlClient = createClient({
  url: 'https://countries.trevorblades.com/',
  exchanges: [cacheExchange, fetchExchange],
  fetchOptions: () => {
    return { headers: {} }
  },
})

const HydrateAtoms = ({ children }) => {
  useHydrateAtoms([[clientAtom, urqlClient]])
  return children
}

export default function MyApp({ Component, pageProps }) {
  return (
    <UrqlProvider value={urqlClient}>
      <Provider>
        <HydrateAtoms>
          <Suspense fallback="Loading...">
            <Component {...pageProps} />
          </Suspense>
        </HydrateAtoms>
      </Provider>
    </UrqlProvider>
  )
}
```

---

### Extensions Valtio (`docs/extensions/valtio.mdx`)

---
title: Valtio
description: This doc describes Valtio extension.
nav: 4.98
keywords: valtio,proxy
published: false
---

Jotai's state resides in React, but sometimes it would be nice
to interact with the world outside React.

Valtio provides a proxy interface that can be used to store some values
and sync with atoms in Jotai.

This only uses the vanilla api of valtio.

### Install

You have to install `valtio` and `jotai-valtio` to use this feature.

```
npm install valtio jotai-valtio
```

## atomWithProxy

`atomWithProxy` creates a new atom with valtio proxy.
It's two-way binding and you can change the value from both ends.

```jsx
import { useAtom } from 'jotai'
import { atomWithProxy } from 'jotai-valtio'
import { proxy } from 'valtio/vanilla'

const proxyState = proxy({ count: 0 })
const stateAtom = atomWithProxy(proxyState)
const Counter = () => {
  const [state, setState] = useAtom(stateAtom)

  return (
    <>
      count: {state.count}
      <button
        onClick={() => setState((prev) => ({ ...prev, count: prev.count + 1 }))}
      >
        inc atom
      </button>
      <button
        onClick={() => {
          ++proxyState.count
        }}
      >
        inc proxy
      </button>
    </>
  )
}
```

### Parameters

```
atomWithProxy(proxyObject, options?)
```

**proxyObject** (required): the Valtio proxy object you want to derive the atom from

**options.sync** (optional): makes the atom update synchronously instead of waiting for batched updates, similar to [`valtio/useSnapshot`](https://github.com/pmndrs/valtio#update-synchronously). This will result in more renders, but have more guarantees that it syncs with other Jotai atoms.

```
atomWithProxy(proxyObject, { sync: true })
```

### Examples

<Stackblitz id="vitejs-vite-wmsazx" file="src%2FApp.tsx" />

## mutableAtom

`mutableAtom` wraps a value in a self-aware Valtio proxy. You can make changes to it in the same way you would to a normal js-object.

Count value is stored under the `value` property.

```jsx
const countProxyAtom = mutableAtom(0)

function IncrementButton() {
  const countProxy = useAtomValue(countProxyAtom)
  return <button onClick={() => ++countProxy.value}>+</button>
}
```

### Parameters

```js
mutableAtom(value, options?)
```

**value** (required): the value to proxy.

**options.proxyFn** (optional): allows customization with `proxyFn` for custom proxy functions. Can be `proxy` (default) or a custom function.

### Examples

<Stackblitz id="vitejs-vite-wmsazx" file="src%2FApp.tsx" />

### Caution on Mutating Proxies

Be careful to not mutate the proxy directly in the atom's read function or during render. Doing so could cause an infinite render loop.

```ts
const countProxyAtom = mutableAtom(0)

atom(
  (get) => {
    const countProxy = get(countProxyAtom)
    ++countProxy.value // This will cause an infinite loop
  },
  (get, set) => {
    const countProxy = get(countProxyAtom)
    ++countProxy.value // This is fine
  },
)
```

---

### Extensions Xstate (`docs/extensions/xstate.mdx`)

---
title: XState
description: This doc describes XState extension.
nav: 4.05
keywords: xstate,machine,atomwithmachine
---

Jotai's state management is primitive and flexible,
but that sometimes means too free.
XState is a sophisticated library to provide
a better and safer abstraction for state management.

### Install

You have to install `xstate` and `jotai-xstate` to use this feature.

```
npm install xstate jotai-xstate
```

## atomWithMachine

`atomWithMachine` creates a new atom with XState machine.
It receives a function `getMachine` to create a new machine.
`getMachine` is invoked at the first use with `get` argument,
with which you can read other atom values.

```
/* Detailed source-code truncated for AI context efficiency. */
```

### Restartable machine stored in a global Provider (provider-less mode)

When your machine reaches its final state it cannot receive any more events.
If your atomWithMachine is initialized in global store (aka provider-less mode),
to restart it you need to send a `RESTART` event to your machine like so:

```tsx
import { RESTART } from 'jotai-xstate'

const YourComponent = () => {
  const [current, send] = useAtom(yourMachineAtom)

  const isFinalState = current.matches('myFinalState')

  useEffect(() => {
    // restart globally initialized machine on component unmount
    return () => {
      if (isFinalState) send(RESTART)
    }
  }, [isFinalState])
}
```

### Examples

Check examples with atomWithMachine:

<Stackblitz id="vitejs-vite-oqfhy4" file="src%2FApp.tsx" />

Restartable machine:

<Stackblitz id="vitejs-vite-tqdtym" file="src%2FApp.tsx" />

### Tutorials

Check out a course about Jotai and XState.

[Complex State Management in React with Jotai and XState](https://egghead.io/courses/complex-state-management-in-react-with-jotai-and-xstate-3be0a740)

(Note: In the course, it uses `jotai/xstate` which is supersede by `jotai-xstate`.)

---

### Extensions Zustand (`docs/extensions/zustand.mdx`)

---
title: Zustand
description: This doc describes Zustand extension.
nav: 4.98
keywords: zustand
published: false
---

Jotai's state resides in React, but sometimes it would be nice
to interact with the world outside React.

Zustand provides a store interface that can be used to hold some values
and sync with atoms in Jotai.

This only uses the vanilla api of zustand.

### Install

You have to install `zustand` and `jotai-zustand` to use this feature.

```
npm install zustand jotai-zustand
```

## atomWithStore

`atomWithStore` creates a new atom with zustand store.
It's two-way binding and you can change the value from both ends.

```jsx
import { useAtom } from 'jotai'
import { atomWithStore } from 'jotai-zustand'
import create from 'zustand/vanilla'

const store = create(() => ({ count: 0 }))
const stateAtom = atomWithStore(store)
const Counter = () => {
  const [state, setState] = useAtom(stateAtom)

  return (
    <>
      count: {state.count}
      <button
        onClick={() => setState((prev) => ({ ...prev, count: prev.count + 1 }))}
      >
        button
      </button>
    </>
  )
}
```

### Examples

<Stackblitz id="vitejs-vite-kfzyun" file="src%2FApp.tsx" />

---

### Guides Async (`docs/guides/async.mdx`)

---
title: Async
description: This doc describes about the behavior with async.
nav: 8.99
keywords: async
published: false
---

Using async atoms, you gain access to real-world data while still managing them directly from your atoms and with incredible ease.

We can separate them in two main categories:

- Async read atoms: async request is started instantly as soon as you try to get its value. You could relate to them as "smart getters".
- Async write atoms: async request is started at a specific moment. You could relate to them as "actions".

## Async read atom

The `read` function of an atom can return a promise.

```js
const countAtom = atom(1)
const asyncAtom = atom(async (get) => get(countAtom) * 2)
```

Jotai is inherently leveraging `Suspense` to handle asynchronous flows.

```jsx
const ComponentUsingAsyncAtoms = () => {
  const [num] = useAtom(asyncAtom)
  // here `num` is always `number` even though asyncAtom returns a Promise
}
const App = () => {
  return (
    <Suspense fallback={/* What to show while suspended */}>
      <ComponentUsingAsyncAtoms />
    </Suspense>
  )
}
```

Alternatively, you could avoid the inherent suspending that Jotai does for you, by wrapping your atoms with the [`loadable` API](../utilities/async.mdx#loadable), or by reading the atom with [`useAtomValueRaw`](../core/use-atom.mdx#useatomvalueraw) instead of `useAtomValue`.

If another atom uses an async atom, it will return a promise. So, we need to make the atom also async.

```js
const anotherAtom = atom(async (get) => (await get(asyncAtom)) / 2)
```

This also applies to an atom with write function.

```js
const asyncAtom = atom(async (get) => ...)
const writeAtom = atom(null, async (get, set, payload) => {
  await get(asyncAtom)
  // ...
})
```

## Async write atom

Async write atoms are another kind of async atom. When the `write` function of atom returns a promise.

```js
const countAtom = atom(1)
const asyncIncrementAtom = atom(null, async (get, set) => {
  // await something
  set(countAtom, get(countAtom) + 1)
})

const Component = () => {
  const [, increment] = useAtom(asyncIncrementAtom)
  const handleClick = () => {
    increment()
  }
  // ...
}
```

## Async sometimes

An interesting pattern that can be achieved with Jotai is switching from async to sync to trigger suspending when wanted.

```js
const request = async () =>
  fetch('https://jsonplaceholder.typicode.com/todos/1').then((res) =>
    res.json(),
  )
const baseAtom = atom(0)
const Component = () => {
  const [value, setValue] = useAtom(baseAtom)
  const handleClick = () => {
    setValue(request()) // Will suspend until request resolves
  }
  // ...
}
```

### Usage in TypeScript

In TypeScript `atom(0)` is inferred as `PrimitiveAtom<number>`. It cannot accept `Promise<number>` as a value so preceding code would not typecheck. To accommodate for that you need to type your atom explicitly and add `Promise<number>` as accepted value.

```ts
const baseAtom = atom<number | Promise<number>>(0) // Will accept sync and async values
```

## Async forever

Sometimes you may want to suspend until an unpredetermined moment (or never).

```js
const baseAtom = atom(new Promise(() => {})) // Will be suspend until set otherwise
```

## Suspense

Async support is first class in Jotai. It fully leverages React Suspense at its core.

> Technically, Suspense usage other than React.lazy is still unsupported / undocumented in React 17. If this is blocking, so you can still use the [`loadable` API](../utilities/async.mdx) to avoid suspending

To use async atoms, you need to wrap your component tree with `<Suspense>`.

> If you have a `<Provider>`, place **at least one** `<Suspense>` inside said `<Provider>`; otherwise, it may cause an endless loop while rendering the components.

```jsx
const App = () => (
  <Provider>
    <Suspense fallback="Loading...">
      <Layout />
    </Suspense>
  </Provider>
)
```

Having more `<Suspense>`s in the component tree is also possible and must be considered to profit from Jotai inherent handling at best.

---

### Guides Atoms In Atom (`docs/guides/atoms-in-atom.mdx`)

---
title: Atoms in atom
nav: 8.12
---

`atom()` creates an atom config, which is an object, but it doesn't hold a value.
Atom configs don't have string keys and we identify them with referential equality.
In other words, we can use an atom config like a key.

### Storing an atom config in useState

First things first, we can store an atom config in useState.

```jsx
const Component = ({ atom1, atom2 }) => {
  const [selectedAtom, setSelectedAtom] = useState(atom1)
  const [value] = useAtom(selectedAtom)
  return (
    <div>
      Selected value: {value}
      <button onClick={() => setSelectedAtom(atom1)}>Select an atom</button>
      <button onClick={() => setSelectedAtom(atom2)}>
        Select another atom
      </button>
    </div>
  )
}
```

Note that we can pass atoms configs as props.

It might not make any sense, but we could create an atom config on demand.

```jsx
const Component = () => {
  const [currentAtom, setCurrentAtom] = useState(() => atom(0))
  const [count, setCount] = useAtom(currentAtom)
  return (
    <div>
      Count: {count} <button onClick={() => setCount((c) => c + 1)}>+1</button>
      <button onClick={() => setCurrentAtom(atom(0))}>Create new</button>
    </div>
  )
}
```

### Storing an atom config in atom

Likewise, we can store an atom config as a value of another atom.

```jsx
const firstNameAtom = atom('Tanjiro')
const lastNameAtom = atom('Kamado')

const showingNameAtom = atom(firstNameAtom)

const Component = () => {
  const [nameAtom, setNameAtom] = useAtom(showingNameAtom)
  const [name] = useAtom(nameAtom)
  return (
    <div>
      Name: {name}
      <button onClick={() => setNameAtom(firstNameAtom)}>
        Show First Name
      </button>
      <button onClick={() => setNameAtom(lastNameAtom)}>Show Last Name</button>
    </div>
  )
}
```

It's possible to create a derived atom.

```js
const derivedNameAtom = atom((get) => {
  const nameAtom = get(showingNameAtom)
  return get(nameAtom)
})

// Or a shorter version
const derivedNameAtom = atom((get) => get(get(showingNameAtom)))
```

To avoid confusing what is in atoms, naming atoms explicitly would be important.
Also, TypeScript type information would be helpful.

### Storing an array of atom configs in atom

Finally, the atoms in atom pattern is to store an array of atom config into an atom.

```jsx
const countsAtom = atom([atom(1), atom(2), atom(3)])

const Counter = ({ countAtom }) => {
  const [count, setCount] = useAtom(countAtom)
  return (
    <div>
      {count} <button onClick={() => setCount((c) => c + 1)}>+1</button>
    </div>
  )
}

const Parent = () => {
  const [counts, setCounts] = useAtom(countsAtom)
  const addNewCount = () => {
    const newAtom = atom(0)
    setCounts((prev) => [...prev, newAtom])
  }
  return (
    <div>
      {counts.map((countAtom) => (
        <Counter countAtom={countAtom} key={countAtom} />
      ))}
      <button onClick={addNewCount}>Add</button>
    </div>
  )
}
```

The benefit of this approach is, if you increment a count,
only the corresponding Counter component re-renders and no other components re-render.

It is important to note that `anAtom.toString()` returns a unique id, which can be used as a `key` in a map.

#### Hint for TypeScript users

```jsx
<Counter countAtom={countAtom} key={`${countAtom}`} />
```

### Storing a map of atom configs in atom

Likewise, we can store an object map instead of an array.

```jsx
const pricesAtom = atom({
  apple: atom(15),
  orange: atom(12),
  pineapple: atom(25),
})

const Fruit = ({ name, priceAtom }) => {
  const [price] = useAtom(priceAtom)
  return (
    <div>
      {name}: {price}
    </div>
  )
}

const Parent = () => {
  const [prices] = useAtom(pricesAtom)
  return (
    <div>
      {Object.keys(prices).map((name) => (
        <Fruit name={name} priceAtom={prices[name]} key={name} />
      ))}
    </div>
  )
}
```

---

### Guides Composing Atoms (`docs/guides/composing-atoms.mdx`)

---
title: Composing atoms
nav: 8.11
---

The `atom` function provided by library is very primitive,
but it's also so flexible that you can combine multiple atoms
to implement a functionality.

> Note again that `atom()` creates an atom config, which is an object
> to define a behavior of the atom.

Let's recap how we can derive an atom.

### Basic derived atoms

Here's one of the simplest examples of a derived atom:

```js
export const textAtom = atom('hello')
export const textLenAtom = atom((get) => get(textAtom).length)
```

The `textLenAtom` is called read-only atom, because
it doesn't have a `write` function defined.

The following is another simple example with the `write` function:

```js
const textAtom = atom('hello')
export const textUpperCaseAtom = atom(
  (get) => get(textAtom).toUpperCase(),
  (_get, set, newText) => set(textAtom, newText),
)
```

In this case, `textUpperCaseAtom` is capable to set the original `textAtom`.
So, we can only export `textUpperCaseAtom` and can hide
`textAtom` in a smaller scope.

Now, let's see some real examples.

### Overriding default atom values

Suppose we have a read-only atom.
Obviously read-only atoms are not writable, but we can combine two atoms
to override the read-only atom value.

```js
const rawNumberAtom = atom(10.1) // can be exported
const roundNumberAtom = atom((get) => Math.round(get(rawNumberAtom)))
const overwrittenAtom = atom(null)
export const numberAtom = atom(
  (get) => get(overwrittenAtom) ?? get(roundNumberAtom),
  (get, set, newValue) => {
    const nextValue =
      typeof newValue === 'function' ? newValue(get(numberAtom)) : newValue
    set(overwrittenAtom, nextValue)
  },
)
```

The final `numberAtom` just works like a normal primitive atom like `atom(10)`.
If you set a number value, it will override the `overwrittenAtom` value,
and if you set `null`, it will be the `roundNumberAtom` value.

The reusable implementation is available as `atomWithDefault`
in `jotai/utils`. See [atomWithDefault](../utilities/resettable.mdx).

Next, let's see another example to sync with external value.

### Syncing atom values with external values

There are some external values we want to deal with.
`localStorage` is the one. Another is `window.title`.

Let's see how to create an atom that is in sync with `localStorage`.

```js
const baseAtom = atom(localStorage.getItem('mykey') || '')
export const persistedAtom = atom(
  (get) => get(baseAtom),
  (get, set, newValue) => {
    const nextValue =
      typeof newValue === 'function' ? newValue(get(baseAtom)) : newValue
    set(baseAtom, nextValue)
    localStorage.setItem('mykey', nextValue)
  },
)
```

The `persistedAtom` works like a primitive atom, but its value
is persisted in `localStorage`.

The reusable implementation is available as `atomWithStorage`
in `jotai/utils`. See [atomWithStorage](../utilities/storage.mdx).

There is a caveat with this usage. While atom config doesn't hold a value,
the external value is a singleton value.
So, if we use this atom in two different Providers,
There will be an inconsistency between the two `persistedAtom` values.
This could be solved if the external value had a subscription mechanism.

For example, `atomWithProxy` in `jotai-valtio` comes with subscription,
so we don't have such a limitation. Values in different Providers
will be in sync.

Back to the main topic, let's explore another example.

### Extending atoms with `atomWith*` utils

We have several utils whose names start with `atomWith`.
They create an atom with a certain functionality.
Unfortunately, we can't combine two atom utils.
For example, `atomWithStorage` and `atomWithReducer`
can't be used to define a single atom.

In such a case, we need to derive an atom by ourselves.
Let's try adding reducer functionality to `atomWithStorage`:

```js
const reducer = ...
const baseAtom = atomWithStorage('mykey', '')
export const derivedAtom = atom(
  (get) => get(baseAtom),
  (get, set, action) => {
    set(baseAtom, reducer(get(baseAtom), action))
  }
)
```

This is easy, because in this case, `atomWithReducer`
is a simple implementation compared to `atomWithStorage`.

For more complex cases, it wouldn't be very easy.
It would still be a open research field.

Finally, let's see another example with actions.

### Action atoms

This should be known pattern as it's described in README.
Nonetheless, it might to be useful to revisit.

Let's create a counter that you can only increment or decrement by one.

One solution is `atomWithReducer`:

```js
const countAtom = atomWithReducer(0, (prev, action) => {
  if (action === 'INC') {
    return prev + 1
  }
  if (action === 'DEC') {
    return prev - 1
  }
  throw new Error('unknown action')
})
```

This is fine, but not very atomic.
If we want to get benefit from code splitting / lazy loading,
We want to create write only atoms, or action atoms.

```js
const baseAtom = atom(0) // do not export
export const countAtom = atom((get) => get(baseAtom)) // read only
export const incAtom = atom(null, (_get, set) => {
  set(baseAtom, (prev) => prev + 1)
})
export const decAtom = atom(null, (_get, set) => {
  set(baseAtom, (prev) => prev - 1)
})
```

This is more atomic and looks like a Jotai way.

You can also create an action atom that will call another action atom:

```js
// continued from the previous code
export const dispatchAtom = atom(null, (_get, set, action) => {
  if (action === 'INC') {
    set(incAtom)
  } else if (action === 'DEC') {
    set(decAtom)
  } else {
    throw new Error('unknown action')
  }
})
```

Why do we want it? Because it will be used only when needed.
It allows code splitting and dead code elimination.

### In summary

Atoms are building block.
By composing atoms based on other atoms,
we can implement complicated logic.
This is not only for read derived atoms, but also for write action atoms.

Essentially, atoms are like functions, so composing atoms is
like composing functions with other functions.

When you compose atoms, prefer a wide graph over a deep one: an atom that derives from a few others is fine, but a long chain where each atom derives from the previous one is bounded by the JavaScript call stack and can overflow when read. See [dependency graph depth](performance.mdx#dependency-graph-depth) in the performance guide for details and how to flatten such chains.

**Note**: We mentioned that our atoms can contain any kind of data, it can be a string, Blob, Observer, anything really. There is just one exception. Because derived atoms are defined using a function, Jotai will not understand if we pass it a function that isn't exactly a pure getter.
So what you can do is simply wrap your function in an object.

```js
const doublerAtom = atom({ callback: (n) => n * 2 })
// Usage
const [doubler] = useAtom(doublerAtom)
const doubledValue = doubler.callback(50) // Will compute to 100
```

---

### Guides Core Internals (`docs/guides/core-internals.mdx`)

---
title: Core internals
description: A simplified version of the core implementation
nav: 8.10
---

This guide is beneficial for those who want to understand the core implementation of Jotai. It's not meant to be a complete example of the
core implementation but rather a simplified version. It's inspired by the collection of tweets by Daishi Kato([@dai_shi](https://twitter.com/dai_shi)).

### First Version

Let's start with an easy example. An atom is just a function that will return a configuration object. We are using WeakMap to map atom with their state.
WeakMap doesn't keep its keys in memory, so if an atom is garbage collected, its state will be garbage collected too. This helps avoid memory leaks.

```js
import { useState, useEffect } from 'react'

// atom function returns a config object which contains initial value
export const atom = (initialValue) => ({ init: initialValue })

// we need to keep track of the state of the atom.
// we are using weakmap to avoid memory leaks
const atomStateMap = new WeakMap()
const getAtomState = (atom) => {
  let atomState = atomStateMap.get(atom)
  if (!atomState) {
    atomState = { value: atom.init, listeners: new Set() }
    atomStateMap.set(atom, atomState)
  }
  return atomState
}

// useAtom hook returns a tuple of the current value
// and a function to update the atom's value
export const useAtom = (atom) => {
  const atomState = getAtomState(atom)
  const [value, setValue] = useState(atomState.value)
  useEffect(() => {
    const callback = () => setValue(atomState.value)

    // same atom can be used at multiple components, so we need to
    // keep listening for atom's state change till component is unmounted.
    atomState.listeners.add(callback)
    callback()
    return () => atomState.listeners.delete(callback)
  }, [atomState])

  const setAtom = (nextValue) => {
    atomState.value = nextValue

    // let all the subscribed components know that the atom's state has changed
    atomState.listeners.forEach((l) => l())
  }

  return [value, setAtom]
}
```

Here's an example using our simplified atom implementation. [Counter example](https://codesandbox.io/s/zealous-field-z2xk6?file=/src/App.js)

Ref tweet: [Demystifying the internal of jotai](https://twitter.com/dai_shi/status/1484835169475653634)

### Second Version

Hang on! We can do better. In Jotai, we can create derived atom. A derived atom is an atom that depends on other atoms.

```js
const priceAtom = atom(10)
const readOnlyAtom = atom((get) => get(priceAtom) * 2)
const writeOnlyAtom = atom(
  null, // it's a convention to pass `null` for the first argument
  (get, set, args) => {
    set(priceAtom, get(priceAtom) - args)
  },
)
const readWriteAtom = atom(
  (get) => get(priceAtom) * 2,
  (get, set, newPrice) => {
    set(priceAtom, newPrice / 2)
    // you can set as many atoms as you want at the same time
  },
)
```

To keep track of all the dependents, we need to add one more property to the atom's state. Let's say atom X depends on atom Y,
so when we update atom Y, we also update atom X. This is called dependency tracking.

```js
const atomState = {
  value: atom.init,
  listeners: new Set(),
  dependents: new Set(),
}
```

We now need to create functions for reading and writing an atom that can handle updating dependent atoms' state.

```
/* Detailed source-code truncated for AI context efficiency. */
```

Here is an example using our derived atom implementation. [Derived counter example](https://codesandbox.io/s/affectionate-chandrasekhar-nuxms?file=/src/App.js)

Ref tweet: [Supporting derived atoms](https://twitter.com/dai_shi/status/1485434083778117632)

---

### Guides Debugging (`docs/guides/debugging.mdx`)

---
title: Debugging
nav: 8.07
keywords: debug,labels,devtools,freeze
---

In basic apps, `console.log` can be our best friend for debugging atoms, but when applications get bigger and we have more atoms to use, logging would not be a good way of debugging atoms.
Jotai provides two ways of debugging atoms, **React Dev Tools** and **Redux Dev tools**. For reading values and simple debugging, React Dev Tools might suit you, but for more complicated tasks like Time-travelling and setting values, Redux Dev Tools would be a better option.

## Debug labels

It is worth mentioning that we have a concept called **Debug labels** in Jotai which may help us with debugging.
By default each Jotai state has the label like `1:<no debugLabel>` with number being internal `key` assigned to each atom automatically. But you can add labels to atoms to help you distinguish them more easily with `debugLabel`.

```js
const countAtom = atom(0)
// countAtom's debugLabel by default is 'atom1'
if (process.env.NODE_ENV !== 'production') {
  countAtom.debugLabel = 'count'
  // debugLabel is 'count' now
}
```

Jotai provides both a Babel and a SWC plugin, that adds a debugLabel automatically to every atom, which makes things easier for us. For more info, check out [jotai-babel](https://github.com/jotaijs/jotai-babel) and [@swc-jotai/debug-label](https://github.com/pmndrs/jotai/blob/main/docs/tools/swc.mdx)

## Using React Dev Tools

You can use [React Dev Tools](https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi)
to inspect Jotai state. To achieve that [useDebugValue](https://react.dev/reference/react/useDebugValue)
is used inside custom hooks. Keep in mind that it only works in dev mode
(such as `NODE_ENV === 'development'`).

### useAtom

`useAtom` calls `useDebugValue` for atom values, so if you select the component that consumes Jotai atoms in React Dev Tools, you would see "Atom" hooks for each atom that is used in the component along with the value it has right now.

### useAtomsDebugValue

`useAtomsDebugValue` catches all atoms in a component tree under Provider (or an entire tree for Provider-less mode), and `useDebugValue` for all atoms values.
If you navigate to the component that has `useAtomsDebugValue` in the React Dev Tools, we can see a custom hook "AtomsDebugValue" which allows you to see all atom values and their dependents.

One use case is to put the hook just under the `Provider` component:

```jsx
const DebugAtoms = () => {
  useAtomsDebugValue()
  return null
}

const Root = () => (
  <Provider>
    <DebugAtoms />
    <App />
  </Provider>
)
```

## Using Redux DevTools

You can also use [Redux DevTools](https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd)
to inspect atoms, with many features like Time-travelling and value dispatching.

### [useAtomDevtools](https://jotai.org/docs/api/devtools#use-atom-devtools)

> `useAtomDevtools` is a React hook that manages ReduxDevTools extension for a particular atom.

If you have a specific atom in mind that you may want to debug, `useAtomDevtools` can be a good option.

```js
const countAtom = atom(0)
// setting countAtom.debugLabel is recommended if we have more atoms

function Counter() {
  const [count, setCount] = useAtom(countAtom)
  useAtomDevtools(countAtom)
}
```

Now if we try `setCount`, we can see that the Redux Dev Tools logs those changes immediately.




#### Time travel

Sometimes we need to switch to a specific value of our atoms' state, with Time travelling this is possible.
You can hover on each action you see in the devtools and see the **Jump** option there, with clicking it you'd be able to switch to that specific value.

#### Pause

If we don't record changes on atoms, we can stop watching those using the **Pausing** feature.



#### Dispatch

It's possible to set values on atoms with the **Dispatch** feature. You can do that by clicking on the **Show Dispatcher** button.

This would set the `countAtoms`'s value to `5`.

> We should note that the value will be parsed by JSON.parse, so pass supported values.

### [useAtomsDevtools](../tools/devtools.mdx)

> `useAtomsDevtools` is a catch-all version of `useAtomDevtools` where it shows all atoms in the store instead of showing a specific one.

We'd recommend this hook if you want to keep track of all of your atoms in one place. It means every action on every atom that is placed in the bottom of this hook (in the React tree) will be caught by the Redux Dev Tools.

Every feature of `useAtomDevtools` is supported in this hook, but there's an extra feature, which includes giving more information about atoms dependents like:

```json
{
  "values": {
    "atom1:count": 0,
    "atom2:doubleCount": 0,
    "atom3:half": 0,
    "atom4:sum": 0
  },
  "dependents": {
    "atom1:count": ["atom1:count", "atom2:doubleCount", "atom4:sum"],
    "atom2:doubleCount": ["atom3:half", "atom4:sum"],
    "atom3:half": ["atom4:sum"],
    "atom4:sum": []
  }
}
```

## Frozen Atoms

To find bugs where you accidentally tried to mutate objects stored in atoms you
could use `freezeAtom` or `freezeAtomCreator`from `jotai/utils` bundle.
Which returns atoms value that is deeply freezed with `Object.freeze`.

### freezeAtom

```ts
freezeAtom(anAtom): AtomType
```

`freezeAtom` takes an existing atom and make it "frozen".
It returns the same atom.
The atom value will be deeply frozen by `Object.freeze`.
It is useful to find bugs where you unintentionally tried
to change objects (states) which can lead to unexpected behavior.
You may use `freezeAtom` with all atoms to prevent this situation.

#### Parameters

**anAtom** (required): An atom you wish to freeze.

#### Examples

```js
import { atom } from 'jotai'
import { freezeAtom } from 'jotai/utils'

const objAtom = freezeAtom(atom({ count: 0 }))
```

### freezeAtomCreator

If you need, you can define a factory for `freezeAtom`.

```ts
import { freezeAtom } from 'jotai/utils'

export function freezeAtomCreator<
  CreateAtom extends (...args: unknown[]) => Atom<unknown>,
>(createAtom: CreateAtom): CreateAtom {
  return ((...args: unknown[]) => freezeAtom(createAtom(...args))) as never
}
```

---

### Guides Initialize Atom On Render (`docs/guides/initialize-atom-on-render.mdx`)

---
title: Initializing state on render
description: How to initialize atom state on initial render
nav: 8.13
---

There are times when you need to create an reusable component which uses atoms.

These atoms' initial state are determined by the props passed to the component.

Below is a basic example illustrating how you can use `Provider` and its prop, `initialValues`, to initialize state.

### Basic Example

> CodeSandbox link: [codesandbox](https://codesandbox.io/s/init-atoms-with-usehydrateatoms-nryk1w).

Consider a basic example where you have a reusable `TextDisplay` component that allows you to display and update plain text.

This component has two child components, `PrettyText` and `UpdateTextInput`.

- `PrettyText` displays the text in blue.
- `UpdateTextInput` is an input field which updates the text value.

As opposed to passing `text` as a prop in the two child components, you decided that the `text` state should be shared between components as an atom.

To make `TextDisplay` component reusable, we take in a prop `initialTextValue`, which determines the initial state of the `text` atom.

To tie `initialTextValue` to `textAtom`, we wrap the child components in a component where we create a new store and pass it to a `Provider` component.

```jsx
const textAtom = atom('')

const PrettyText = () => {
  const [text] = useAtom(textAtom)
  return (
    <>
      <text
        style={{
          color: 'blue',
        }}
      >
        {text}
      </text>
    </>
  )
}

const UpdateTextInput = () => {
  const [text, setText] = useAtom(textAtom)
  const handleInputChange = (e) => {
    setText(e.target.value)
  }
  return (
    <>
      <input onChange={handleInputChange} value={text} />
    </>
  )
}

const HydrateAtoms = ({ initialValues, children }) => {
  // initialising on state with prop on render here
  useHydrateAtoms(initialValues)
  return children
}

export const TextDisplay = ({ initialTextValue }) => (
  <Provider>
    <HydrateAtoms initialValues={[[textAtom, initialTextValue]]}>
      <PrettyText />
      <br />
      <UpdateTextInput />
    </HydrateAtoms>
  </Provider>
)
```

Now, we can easily reuse `TextDisplay` component with different initial text values despite them referencing the "same" atom.

```jsx
export default function App() {
  return (
    <div className="App">
      <TextDisplay initialTextValue="initial text value 1" />

      <TextDisplay initialTextValue="initial text value 2" />
    </div>
  )
}
```

This behavior is due to our child components looking for the lowest common `Provider` ancestor to derive its value.

For more information on `Provider` behavior, please read the docs [here](../core/provider.mdx).

For more complex use cases, check out [Scope extension](../extensions/scope.mdx).

### Using Typescript

`useHydrateAtoms` has overloaded types and typescript cannot extract types from overloaded function. It is recommended to use a `Map` when passing initial atom values to the `useHydrateAtoms`.

Here is a working example:

```tsx
import type { ReactNode } from 'react'
import { Provider, atom, useAtomValue } from 'jotai'
import type { WritableAtom } from 'jotai'
import { useHydrateAtoms } from 'jotai/utils'

const testAtom = atom('')

export default function App() {
  return (
    <Provider>
      <AtomsHydrator atomValues={[[testAtom, 'hello']]}>
        <Component />
      </AtomsHydrator>
    </Provider>
  )
}

//This component contains all the states and the logic
function Component() {
  const testAtomValue = useAtomValue(testAtom)
  return <div>{testAtomValue}</div>
}

function AtomsHydrator({
  atomValues,
  children,
}: {
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  atomValues: Iterable<
    readonly [WritableAtom<unknown, [any], unknown>, unknown]
  >
  children: ReactNode
}) {
  useHydrateAtoms(new Map(atomValues))
  return children
}
```

---

### Guides Migrating To V2 Api (`docs/guides/migrating-to-v2-api.mdx`)

---
title: v2 API migration
description: New "Async" API
nav: 8.0
---

RFC: https://github.com/pmndrs/jotai/discussions/1514

Jotai v1 is released at June 2022, and there has been various feedbacks.
React also proposes first-class support for promises.
Jotai v2 will have a new API.

Unfortunately, there are some breaking changes along with new features.

### What are new features

#### Vanilla library

Jotai comes with vanilla (non-React) functions
and React functions separately.
They are provided from alternate entry points like `jotai/vanilla`.

#### Store API

Jotai exposes store interface so that you can directly manipulate atom values.

```js
import { createStore } from 'jotai' // or from 'jotai/vanilla'

const store = createStore()
store.set(fooAtom, 'foo')

console.log(store.get(fooAtom)) // prints "foo"

const unsub = store.sub(fooAtom, () => {
  console.log('fooAtom value in store is changed')
})
// call unsub() to unsubscribe.
```

You can also create your own React Context to pass a store.

#### More flexible atom `write` function

The write function can accept multiple arguments,
and return a value.

```js
atom(
  (get) => get(...),
  (get, set, arg1, arg2, ...) => {
    ...
    return someValue
  }
)
```

### What are breaking

#### Async atoms are no longer special

Async atoms are just normal atoms with promise values.
Atoms getter functions don't resolve promises.
On the other hand, `useAtom` hook continues to resolve promises.

Some utils like `splitAtom` expects sync atoms,
and won't work with async atoms.

#### Writable atom type is changed (TypeScript only)

```ts
// Old
WritableAtom<Value, Arg, Result extends void | Promise<void>>

// New
WritableAtom<Value, Args extends unknown[], Result>
```

In general, we should avoid using `WritableAtom` type directly.

#### Some functions are dropped

- Provider's `initialValues` prop is removed, because `store` is more flexible.
- Provider's scope props is removed, because you can create own context.
- `abortableAtom` util is removed, because the feature is included by default
- `waitForAll` util is removed, because `Promise.all` just works

### Migration guides

#### Async atoms

`get` function for read function of async atoms
doesn't resolve promises, so you have to put `await` or `.then()`.

In short, the change is something like the following.
(If you are TypeScript users, types will tell where to changes.)

##### Previous API

```js
const asyncAtom = atom(async () => 'hello')
const derivedAtom = atom((get) => get(asyncAtom).toUppercase())
```

##### New API

```js
const asyncAtom = atom(async () => 'hello')
const derivedAtom = atom(async (get) => (await get(asyncAtom)).toUppercase())
// or
const derivedAtom = atom((get) => get(asyncAtom).then((x) => x.toUppercase()))
```

#### Provider's `initialValues` prop

##### Previous API

```jsx
const countAtom = atom(0)

  // in component
  <Provider initialValues={[[countAtom, 1]]}>
    ...
```

##### New API

```jsx
const countAtom = atom(0)

const HydrateAtoms = ({ initialValues, children }) => {
  useHydrateAtoms(initialValues)
  return children
}

  // in component
  <Provider>
    <HydrateAtoms initialValues={[[countAtom, 1]]}>
      ...
```

#### Provider's `scope` prop

##### Previous API

```jsx
const myScope = Symbol()

  // Parent component
  <Provider scope={myScope}>
    ...
  </Provider>

  // Child component
  useAtom(..., myScope)
```

##### New API

```jsx
const MyContext = createContext()
const store = createStore()

  // Parent component
  <MyContext.Provider value={store}>
    ...
  </MyContext.Provider>

  // Child Component
  const store = useContext(MyContext)
  useAtom(..., { store })
```

#### `abortableAtom` util

You no longer need the previous `abortableAtom` util,
because it's now supported with the normal `atom`.

##### Previous API

```js
const asyncAtom = abortableAtom(async (get, { signal }) => {
 ...
}
```

##### New API

```js
const asyncAtom = atom(async (get, { signal }) => {
  ...
}
```

#### `waitForAll` util

You no longer need the previous `waitForAll` util,
because we can use native Promise APIs.

##### Previous API

```js
const allAtom = waitForAll([fooAtom, barAtom])
```

##### New API

```js
const allAtom = atom((get) => Promise.all([get(fooAtom), get(barAtom)]))
```

Note that creating an atom in render function can cause [infinite loop](../core/atom.mdx#note-about-creating-an-atom-in-render-function)

#### `splitAtom` util (or some other utils) with async atoms

`splitAtom` util only accepts sync atoms.
You need to unwrap async atoms before passing.

This applies to some other utils like `atomsWithQuery` from `jotai-tanstack-query`.

##### Previous API

```js
const splittedAtom = splitAtom(asyncArrayAtom)
```

##### New API

```js
const splittedAtom = splitAtom(unwrap(asyncArrayAtom, () => []))
```

As of writing, `unwrap` is unstable and not documented.
You can instead use `loadable`, which gives more control on loading status.
If you need to use `<Suspense>`, atoms-in-atom pattern would help.

For more information, refer the following discussions:

- https://github.com/pmndrs/jotai/discussions/1615
- https://github.com/jotaijs/jotai-tanstack-query/issues/21
- https://github.com/pmndrs/jotai/discussions/1751

### Some other changes

#### Utils

- `atomWithStorage` util's `delayInit` is removed as being default. Also it will always render `initialValue` on first render, and the stored value, if any, on subsequent renders. The new behavior differs from v1. See https://github.com/pmndrs/jotai/discussions/1737 for more information.
- `useHydrateAtoms` can only accept writable atoms.

#### Import statements

The v2 API is also provided from alternate entry points for library authors and non-React users.

- `jotai/vanilla`
- `jotai/vanilla/utils`
- `jotai/react`
- `jotai/react/utils`

```js
// Available since v1.11.0
import { atom } from 'jotai/vanilla'
import { useAtom } from 'jotai/react'

// Available since v2.0.0
import { atom } from 'jotai' // is same as 'jotai/vanilla'
import { useAtom } from 'jotai' // is same as 'jotai/react'
```

Note: If you are not using ESM, you want to prefer using `jotai/vanilla` etc. instead of `jotai`, for better tree shaking.

---

### Guides Migrating To V3 (`docs/guides/migrating-to-v3.mdx`)

---
title: v3 migration
description: How to migrate to Jotai v3
nav: 8.01
---

Roadmap: https://github.com/pmndrs/jotai/discussions/2889

Jotai v3 focuses on modernizing the package.
The public API is unchanged: `useAtom`, `useAtomValue` and `useSetAtom`
keep the same signatures and the same behavior for the vast majority of use cases.
If your app runs on Jotai v2 without deprecation warnings,
it should run on v3 as is.

There is one subtle timing change worth knowing about, see
[useAtomValue: a subtle mount-timing change](../core/use-atom.mdx#a-subtle-mount-timing-change-in-v3)
below.

### Requirement changes

The minimum requirements are raised:

- React 18 (v2 supports React 17)
- TypeScript 5.5 (v2 supports TypeScript 3.8)
- Node.js `>=22.12.0` (v2 supports Node.js 12.20)

### Packaging changes

#### ESM only

The CJS, UMD and SystemJS builds are no longer provided.
Modern bundlers work with the ESM build out of the box.
The supported Node.js versions can load it
even from CJS code with `require()`.

The package `exports` only expose the public entry points:

- `jotai`
- `jotai/utils`
- `jotai/vanilla`
- `jotai/vanilla/utils`
- `jotai/vanilla/internals`
- `jotai/react`
- `jotai/react/utils`

Importing other files in the package directly no longer works.

#### `process.env.NODE_ENV` is used directly

The published files read `process.env.NODE_ENV` directly
to omit development-only checks in production.
Bundlers handle it by default.
If you load Jotai in a browser without a bundler
(for example, with import maps),
you need to define it by yourself.

```js
globalThis.process ??= { env: { NODE_ENV: 'production' } }
```

#### ES2020 syntax

The published files are compiled with the ES2020 target.
If you need to support older browsers,
transpile the package in your build.

### Removed features

#### `atomFamily` util

It's moved to the `jotai-family` package.

##### Previous API

```js
import { atomFamily } from 'jotai/utils'
```

##### New API

```js
// npm install jotai-family
import { atomFamily } from 'jotai-family'
```

#### `loadable` util

Use the `unwrap` util instead.
The previous behavior can be implemented in userland:

```js
import { atom } from 'jotai'
import { unwrap } from 'jotai/utils'

function loadable(anAtom) {
  const LOADING = { state: 'loading' }
  const unwrappedAtom = unwrap(anAtom, () => LOADING)
  return atom((get) => {
    try {
      const data = get(unwrappedAtom)
      if (data === LOADING) {
        return LOADING
      }
      return { state: 'hasData', data }
    } catch (error) {
      return { state: 'hasError', error }
    }
  })
}
```

#### `jotai/babel` plugins

They are moved to the `jotai-babel` package.

##### Previous API

```js
// babel config
plugins: ['jotai/babel/plugin-react-refresh']
```

##### New API

```js
// npm install jotai-babel
plugins: ['jotai-babel/plugin-react-refresh']
```

#### `setSelf` option in the read function

##### Previous API

```js
const anAtom = atom(async (get, { setSelf }) => {
  // ...
})
```

##### New API

There is no direct replacement.
Depending on the use case,
`onMount` or [jotai-effect](https://github.com/jotaijs/jotai-effect)
would cover it.

#### `delay` option in `useAtom` and `useAtomValue`

##### Previous API

```js
const value = useAtomValue(anAtom, { delay: 100 })
```

##### New API

Create a custom hook:

```js
import { useEffect, useState } from 'react'
import { useStore } from 'jotai'

function useAtomValueWithDelay(anAtom, { delay }) {
  const store = useStore()
  const [value, setValue] = useState(() => store.get(anAtom))
  useEffect(() => {
    const unsub = store.sub(anAtom, () => {
      setTimeout(() => setValue(store.get(anAtom)), delay)
    })
    return unsub
  }, [store, anAtom, delay])
  return value
}
```

### New hooks for advanced users

React 19 introduces `React.use()`, letting a component suspend by reading a
promise during render. `useAtomValue` uses it when available, and falls back
to the previous behavior on React 18. Splitting that logic out enables two
lower-level hooks:

- [`useAtomValueRaw`](../core/use-atom.mdx#useatomvalueraw): like
  `useAtomValue`, but it never suspends. An async atom's value is returned
  without being consumed through React's `use()`.
- [`useAtomValueRawSync`](../core/use-atom.mdx#useatomvaluerawsync): the same
  idea, built on `useSyncExternalStore`. It trades concurrent rendering for
  no tearing and no missed update around mount.

You don't need either hook to migrate. `useAtomValue` keeps working as the
default choice. See [Choosing a hook](../core/use-atom.mdx#choosing-a-hook)
for when to reach for them.

---

### Guides Nextjs (`docs/guides/nextjs.mdx`)

---
title: Next.js
description: How to use Jotai with Next.js
nav: 8.03
keywords: next,nextjs
---

### Hydration

Jotai has support for hydration of atoms with `useHydrateAtoms`. The documentation for the hook can be seen [here](../utilities/ssr.mdx).

### Browser storage

Next.js still prerenders client components during static export, so browser storage APIs such as `localStorage` and `sessionStorage` are not available during the server render.

If you use `atomWithStorage` with `createJSONStorage`, avoid referencing browser storage globals directly. Use `window` behind a server guard instead:

```js
import { atomWithStorage, createJSONStorage } from 'jotai/utils'

const storage = createJSONStorage(() =>
  typeof window !== 'undefined' ? window.sessionStorage : undefined,
)

const someAtom = atomWithStorage('some-key', someInitialValue, storage)
```

If the rendered UI depends on the stored value, render that subtree only on the client to avoid hydration mismatches:

```js
import dynamic from 'next/dynamic'

const StoredPreferences = dynamic(
  () => import('../components/StoredPreferences'),
  {
    ssr: false,
  },
)
```

See the [storage documentation](../utilities/storage.mdx#server-side-rendering) for more details.

### Sync with router

It's possible to sync Jotai with the router. You can achieve this with `atomWithHash`:

```js
const pageAtom = atomWithHash('page', 1, {
  replaceState: true,
  subscribe: (callback) => {
    Router.events.on('routeChangeComplete', callback)
    window.addEventListener('hashchange', callback)
    return () => {
      Router.events.off('routeChangeComplete', callback)
      window.removeEventListener('hashchange', callback)
    }
  },
})
```

This way you have full control over what [router event](https://nextjs.org/docs/api-reference/next/router#routerevents) you want to subscribe to.

> #### In Next.js 13
>
> As of Next.js 13 there have been some changes to the `Router.events.on()` which no longer expose events. There are plans in the [App Router Roadmap](https://beta.nextjs.org/docs/app-directory-roadmap#planned-features) for event intercepting and hash handling. However there is no ETA on when this will be available or what it will look like. For now when trying to the `atomWithHash()` you will not get the atom loading with any data when navigating using the router, only when the page is reloaded or the component is rerendered. It is also recommended that you set the `setHash` option to `replaceState` as Next.js appears to use window.history in the background and this will allow the user to use the browser back button.

### You can't return promises in server side rendering

It's important to note that you can't return promises with SSR - However, it's possible to guard against it inside the atom definition.

If possible use `useHydrateAtoms` to hydrate values from the server.

```js
const postData = atom((get) => {
  const id = get(postId)
  if (isSSR || prefetchedPostData[id]) {
    return prefetchedPostData[id] || EMPTY_POST_DATA
  }
  return fetchData(id) // returns a promise
})
```

### Provider

By default, Jotai uses an implicit global store to keep track of atom values. This is what is referred to as "provider-less" mode. This becomes an issue in SSR scenario because this global store is kept alive and is shared between multiple requests, which can lead to bugs and security risks.

To limit the lifetime of the store to the scope of one request, you need to use a [Provider](../core/provider.mdx) at the root of your app (or a subtree if you're using Jotai only for a part of your application).

```typescript
import { Provider } from 'jotai'

function App({ Component, pageProps }: AppProps) {
  return (
    <Provider>
      <Component {...pageProps} />
    </Provider>
  )
}
```

In this case:

1. `Provider` will hold the state of the atoms used in its subtree instead of the global store.
2. `Provider`'s lifetime will be the same as the app itself, and since the app is recreated on each SSR request we essentially limit the lifetime of the store to a single request as well.

### SWC plugins

Jotai provides SWC plugins for better DX while developing with Next.js. [Find more info in the SWC section.](../tools/swc.mdx)

### Examples

#### Clock

<Stackblitz
  id="stackblitz-starters-nsugnt"
  file="store%2Findex.ts,components%2FClock.tsx"
/>

#### HN Posts

Page Router demo:

<Stackblitz
  id="stackblitz-starters-cnz9lg"
  file="store%2Findex.ts,pages%2F_app.tsx,pages%2Findex.tsx"
/>

App Router [demo on Stackblitz](https://stackblitz.com/edit/jotai-nextjs-app-router-demo?file=store%2Findex.ts,app%2Flayout.tsx,components%2FPost.tsx,app%2Fpage.tsx)

#### Next.js repo

```bash
npx create-next-app --example with-jotai with-jotai-app
```

Here's a [link](https://github.com/vercel/next.js/tree/canary/examples/with-jotai).

---

### Guides Performance (`docs/guides/performance.mdx`)

---
title: Performance
description: How to limit extra re-renders
nav: 8.08
keywords: performance
---

**Note**: This guide has room for improvement. Consider it as FYI for now.

Jotai & React gives us quite a few tools to manage the re-renders that happen in the app lifecycle.
First, please read about the difference [between render & commit](https://legacy.reactjs.org/blog/2018/09/10/introducing-the-react-profiler.html#browsing-commits), because that's very important to understand before going further.

### Cheap renders

As seen in the [core section](../core/atom.mdx), due to React 18 default behaviour (but overall good practice), you have to make sure your component functions are _idempotent_.
They will be called multiple times during the render phase, even at mount. So we need to keep our renders cheap at all cost!

#### Heavy computation

Always make heavy computation outside of the React lifecycle (in actions for example)

Dont's:

```js
// Heavy computation for each item
const selector = (s) => s.filter(heavyComputation)
const Profile = () => {
  const [computed] = useAtom(selectAtom(friendsAtom, selector))
}
```

Do's:

```js
const friendsAtom = atom([])
const fetchFriendsAtom = atom(null, async (get, set, payload) => {
  // Fetch all friends
  const res = await fetch('https://jsonplaceholder.typicode.com/users')
  const data = await res.json()

  // Make heavy computation once only
  const computed = data.filter(heavyComputation)
  set(friendsAtom, computed)
})
// Usage in components
const Profile = () => {
  const [friends] = useAtom(friendsAtom)
}
```

#### Small components

Observed atoms should only re-render small parts of your application that required an update. The less comparison React has to make, the shorter your render time will be.

Dont's:

```jsx
const Profile = () => {
  const [name] = useAtom(nameAtom)
  const [age] = useAtom(ageAtom)
  return (
    <>
      <div>{name}</div>
      <div>{age}</div>
    </>
  )
}
```

Do's:

```jsx
const NameComponent = () => {
  const [name] = useAtom(nameAtom)
  return <div>{name}</div>
}
const AgeComponent = () => {
  const [age] = useAtom(ageAtom)
  return <div>{age}</div>
}
const Profile = () => {
  return (
    <>
      <NameComponent />
      <AgeComponent />
    </>
  )
}
```

### Render on demand

Usually, the main performance overhead will come from re-rendering parts of your app that did not need to, or way more than they should.

We have a few tools to deal with "when" React should render our components. If you have not seen the usage of `useMemo` and `useCallback`, please check the official React documentation for more info before going further.
They are of great use to reduce un-necessary renders where your app is not fluid.

But Jotai also provides its set of tools to handle the "when" our atoms should trigger a re-render.

- Out of the box, Jotai encourages you to split your data into atomic parts, hence each atom is stored separately and will only trigger a re-render when their own value change
- `selectAtom` allows you to subscribe to specific part of a large object and only re-render on value change
- `focusAtom` same as selectAtom, but creating a new atom for the part, giving a setter to update that specific part easily
- `splitAtom` does the work of selectAtom/focusAtom for a dynamic list

While this seems simplistic, it is simple to reason about. That was the goal, let's keep it simple to keep it fast.

#### Frequent or rare updates

Ask yourself whether your atom is usually going to be frequently update or more rarely.
Let's imagine an atom containing an object that changes almost every second, it may not be best suited to "focus" on a specific properties of this object using `focusAtom`, because anyway they will all re-render in the same time, so best adding no overhead and not create any more atoms.

On the other hand, if your object has properties that rarely change, and most importantly, that change independently from the other properties, then you may want to use `focusAtom` or `selectAtom` to prevent un-necessary renders.

### Dependency graph depth

Jotai computes a derived atom by running its read function and synchronously reading each dependency it `get`s, which in turn reads _their_ dependencies. This recursion runs on the JavaScript call stack, so the **depth** of a dependency chain is bounded by the engine's stack size, typically a few thousand levels depending on the engine and how much work each read does.

This is almost never a problem, because real graphs are _wide_ rather than _deep_: an atom usually depends on a handful of others, not on a chain thousands of atoms long. Breadth is essentially unlimited; only chain length matters.

You can hit the limit by accident if you model a collection as a chain of derived atoms (each atom deriving from the previous one) instead of as data inside a single atom. Reading the end of a long enough chain throws a `RangeError: Maximum call stack size exceeded` (or `too much recursion` on Firefox). As of v2, this surfaces at the call site that triggered the read, rather than being silently swallowed, so you find out immediately instead of getting a corrupted graph.

Dont's:

```js
// A linear chain: each atom depends on the previous one. Reading `last`
// recurses once per link, so a few thousand items can overflow the stack.
let prev = atom(0)
for (const value of veryLongList) {
  const node = prev
  prev = atom((get) => get(node) + value)
}
const last = prev
```

Do's:

```js
// Keep the collection in one atom and derive over it in a single read.
// The depth is constant (1) no matter how long the list is.
const listAtom = atom(veryLongList)
const totalAtom = atom((get) => get(listAtom).reduce((a, b) => a + b, 0))
```

For a dynamic list whose items each need to be their own atom (for example, to render and update rows independently), reach for `splitAtom` rather than chaining. It gives you one atom per item that all derive directly from the source atom, so the graph stays one level deep instead of growing with the list.

If you genuinely need a deep computation, run it as a plain reduction inside a single atom's read (or in a write action) rather than spreading it across many chained atoms.

---

### Guides Persistence (`docs/guides/persistence.mdx`)

---
title: Persistence
description: How to persist atoms
nav: 8.14
---

Jotai has an [atomWithStorage function in the utils bundle](../utilities/storage.mdx) for persistence that supports persisting state in `sessionStorage`, `localStorage`, `AsyncStorage`, or the URL hash.

(Note: This guide is a bit outdated and requires some rewrites.)

There are also several alternate implementations here:

### A simple pattern with localStorage

```js
const strAtom = atom(localStorage.getItem('myKey') ?? 'foo')

const strAtomWithPersistence = atom(
  (get) => get(strAtom),
  (get, set, newStr) => {
    set(strAtom, newStr)
    localStorage.setItem('myKey', newStr)
  },
)
```

### A helper function with localStorage and JSON parse

```js
const atomWithLocalStorage = (key, initialValue) => {
  const getInitialValue = () => {
    const item = localStorage.getItem(key)
    if (item !== null) {
      return JSON.parse(item)
    }
    return initialValue
  }
  const baseAtom = atom(getInitialValue())
  const derivedAtom = atom(
    (get) => get(baseAtom),
    (get, set, update) => {
      const nextValue =
        typeof update === 'function' ? update(get(baseAtom)) : update
      set(baseAtom, nextValue)
      localStorage.setItem(key, JSON.stringify(nextValue))
    },
  )
  return derivedAtom
}
```

(Error handling should be added.)

### A helper function with AsyncStorage and JSON parse

This requires [onMount](../core/atom.mdx#onmount-property).

```js
const atomWithAsyncStorage = (key, initialValue) => {
  const baseAtom = atom(initialValue)
  baseAtom.onMount = (setValue) => {
    ;(async () => {
      const item = await AsyncStorage.getItem(key)
      setValue(JSON.parse(item))
    })()
  }
  const derivedAtom = atom(
    (get) => get(baseAtom),
    (get, set, update) => {
      const nextValue =
        typeof update === 'function' ? update(get(baseAtom)) : update
      set(baseAtom, nextValue)
      AsyncStorage.setItem(key, JSON.stringify(nextValue))
    },
  )
  return derivedAtom
}
```

Don't forget to check out the [Async documentation](../guides/async.mdx) for more details on how to use async atoms.

### Example with sessionStorage

Same as AsyncStorage, just use `atomWithStorage` util and override the default storage with the `sessionStorage`

```js
import { atomWithStorage, createJSONStorage } from 'jotai/utils'

const storage = createJSONStorage(() =>
  typeof window !== 'undefined' ? window.sessionStorage : undefined,
)
const someAtom = atomWithStorage('some-key', someInitialValue, storage)
```

### A serialize atom pattern

```tsx
type Actions =
  | { type: 'serialize'; callback: (value: string) => void }
  | { type: 'deserialize'; value: string }

const serializeAtom = atom(null, (get, set, action: Actions) => {
  if (action.type === 'serialize') {
    const obj = {
      todos: get(todosAtom).map(get),
    }
    action.callback(JSON.stringify(obj))
  } else if (action.type === 'deserialize') {
    const obj = JSON.parse(action.value)
    // needs error handling and type checking
    set(
      todosAtom,
      obj.todos.map((todo: Todo) => atom(todo)),
    )
  }
})

const Persist = () => {
  const [, dispatch] = useAtom(serializeAtom)
  const save = () => {
    dispatch({
      type: 'serialize',
      callback: (value) => {
        localStorage.setItem('serializedTodos', value)
      },
    })
  }
  const load = () => {
    const value = localStorage.getItem('serializedTodos')
    if (value) {
      dispatch({ type: 'deserialize', value })
    }
  }
  return (
    <div>
      <button onClick={save}>Save to localStorage</button>
      <button onClick={load}>Load from localStorage</button>
    </div>
  )
}
```

#### Examples

<Stackblitz id="vitejs-vite-zda5uw" file="src%2FApp.tsx" />

### A pattern with atomFamily

```tsx
type Actions =
  | { type: 'serialize'; callback: (value: string) => void }
  | { type: 'deserialize'; value: string }

const serializeAtom = atom(null, (get, set, action: Actions) => {
  if (action.type === 'serialize') {
    const todos = get(todosAtom)
    const todoMap: Record<string, { title: string; completed: boolean }> = {}
    todos.forEach((id) => {
      todoMap[id] = get(todoAtomFamily({ id }))
    })
    const obj = {
      todos,
      todoMap,
      filter: get(filterAtom),
    }
    action.callback(JSON.stringify(obj))
  } else if (action.type === 'deserialize') {
    const obj = JSON.parse(action.value)
    // needs error handling and type checking
    set(filterAtom, obj.filter)
    obj.todos.forEach((id: string) => {
      const todo = obj.todoMap[id]
      set(todoAtomFamily({ id, ...todo }), todo)
    })
    set(todosAtom, obj.todos)
  }
})

const Persist = () => {
  const [, dispatch] = useAtom(serializeAtom)
  const save = () => {
    dispatch({
      type: 'serialize',
      callback: (value) => {
        localStorage.setItem('serializedTodos', value)
      },
    })
  }
  const load = () => {
    const value = localStorage.getItem('serializedTodos')
    if (value) {
      dispatch({ type: 'deserialize', value })
    }
  }
  return (
    <div>
      <button onClick={save}>Save to localStorage</button>
      <button onClick={load}>Load from localStorage</button>
    </div>
  )
}
```

#### Examples

<Stackblitz id="vitejs-vite-z4kjv3" file="src%2FApp.tsx" />

---

### Guides React Native (`docs/guides/react-native.mdx`)

---
title: React Native
description: Using Jotai in React Native
nav: 8.06
keywords: native,ios,android
---

Jotai atoms can be used in React Native applications with absolutely no changes.
Our goal is to always be 100% compatible with React-Native.

### Persistence

When it comes to persistence feature, the implementation specific to React Native are detailed in the [atomWithStorage function in the utils bundle](../utilities/storage.mdx).

### Performance

There is no known specific overhead when using Jotai in your app. Some libraries will add some/lots of additional properties and methods to the stored data for the practical usage, but Jotai behaves differently and you're always manipulating simple stuff that could barely be shortcuted.

Jotai atomic architecture will encourage you to split logic and data, providing a top-most experience to control every one of your render ([or commits, to be precise](https://legacy.reactjs.org/blog/2018/09/10/introducing-the-react-profiler.html#browsing-commits)) and therefore reach the best performances.

And always remember that renders have to be fast, split calculation logic to async actions.

---

### Guides Remix (`docs/guides/remix.mdx`)

---
title: Remix
description: How to use Jotai with Remix
nav: 8.05
keywords: remix
status: draft
---

### Hydration

Jotai has support for hydration of atoms with `useHydrateAtoms`. The documentation for the hook can be seen [here](../utilities/ssr.mdx).

---

### Guides Resettable (`docs/guides/resettable.mdx`)

---
title: Resettable
description: How to use resettable atoms
nav: 8.99
published: false
---

The Jotai core doesn't support resettable atoms.
But you can create those with helper functions from `jotai/utils`.

### Primitive resettable atom with atomWithReset / useResetAtom

```jsx
import { useAtom } from 'jotai'
import { atomWithReset, useResetAtom } from 'jotai/utils'

const todoListAtom = atomWithReset([
  { description: 'Add a todo', checked: false },
])

const TodoList = () => {
  const [todoList, setTodoList] = useAtom(todoListAtom)
  const resetTodoList = useResetAtom(todoListAtom)

  return (
    <>
      <ul>
        {todoList.map((todo) => (
          <li>{todo.description}</li>
        ))}
      </ul>

      <button
        onClick={() =>
          setTodoList((l) => [
            ...l,
            {
              description: `New todo ${new Date().toDateString()}`,
              checked: false,
            },
          ])
        }
      >
        Add todo
      </button>
      <button onClick={resetTodoList}>Reset</button>
    </>
  )
}
```

### Examples

<Stackblitz id="vitejs-vite-2s1vg6" file="src%2FApp.tsx" />

### Derived atom with RESET symbol

```jsx
import { atom, useAtom, useSetAtom } from 'jotai'
import { atomWithReset, useResetAtom, RESET } from 'jotai/utils'

const dollarsAtom = atomWithReset(0)
const centsAtom = atom(
  (get) => get(dollarsAtom) * 100,
  (get, set, newValue: number | typeof RESET) =>
    set(dollarsAtom, newValue === RESET ? newValue : newValue / 100)
)

const ResetExample = () => {
  const [dollars] = useAtom(dollarsAtom)
  const setCents = useSetAtom(centsAtom)
  const resetCents = useResetAtom(centsAtom)

  return (
    <>
      <h3>Current balance ${dollars}</h3>
      <button onClick={() => setCents(100)}>Set $1</button>
      <button onClick={() => setCents(200)}>Set $2</button>
      <button onClick={resetCents}>Reset</button>
    </>
  )
}
```

### Examples

<Stackblitz id="vitejs-vite-wjgquh" file="src%2FApp.tsx" />

---

### Guides Testing (`docs/guides/testing.mdx`)

---
title: Testing
description: How to test your code using Jotai
nav: 8.09
keywords: test,testing
---

We echo the [guiding principles of Testing library](https://testing-library.com/docs/guiding-principles/):

- "The more your tests resemble the way your software is used, the more confidence they can give you."

We encourage you to write tests, like the user would interact with your atoms and components,
therefore treating Jotai as an implementation detail.

Here's an example using [React testing library](https://github.com/testing-library/react-testing-library):

`Counter.tsx`:

```jsx
import { atom, useAtom } from 'jotai'

export const countAtom = atom(0)

export function Counter() {
  const [count, setCount] = useAtom(countAtom)
  return (
    <h1>
      <p>{count}</p>
      <button onClick={() => setCount((c) => c + 1)}>one up</button>
    </h1>
  )
}
```

`Counter.test.ts`:

```jsx
import React from 'react'
import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { Counter } from './Counter'

test('should increment counter', () => {
  // Arrange
  render(<Counter />)

  const counter = screen.getByText('0')
  const incrementButton = screen.getByText('one up')
  // Act
  await userEvent.click(incrementButton)
  // Assert
  expect(counter.textContent).toEqual('1')
})
```

### Injected Values

You may want to inject arbitrary values to your atom before starting some tests.
Maybe the counter should be limited to 100. Let's see how to test that it doesn't increase after reaching 100.
In order to do that, simply use a [Provider](../core/provider.mdx), and export your atom to be filled-in.

```tsx
import React from 'react'
import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { useHydrateAtoms } from 'jotai/utils'
import { countAtom, Counter } from './Counter'
import { Provider } from 'jotai'

const HydrateAtoms = ({ initialValues, children }) => {
  useHydrateAtoms(initialValues)
  return children
}

const TestProvider = ({ initialValues, children }) => (
  <Provider>
    <HydrateAtoms initialValues={initialValues}>{children}</HydrateAtoms>
  </Provider>
)

const CounterProvider = () => {
  return (
    <TestProvider initialValues={[[countAtom, 100]]}>
      <Counter />
    </TestProvider>
  )
}

test('should not increment on max (100)', () => {
  render(<CounterProvider />)

  const counter = screen.getByText('100')
  const incrementButton = screen.getByText('one up')
  await userEvent.click(incrementButton)
  expect(counter.textContent).toEqual('100')
})
```

### Custom hooks

If you have complex atoms, sometimes you want to test them in isolation.

For that, you can use [React Hooks Testing Library](https://github.com/testing-library/react-hooks-testing-library).
Here's an example below:

`countAtom.ts`:

```ts
import { useAtom } from 'jotai'
import { atomWithReducer } from 'jotai/utils'

const reducer = (state: number, action?: 'INCREASE' | 'DECREASE') => {
  switch (action) {
    case 'INCREASE':
      return state + 1
    case 'DECREASE':
      return state - 1
    case undefined:
      return state
  }
}
export const countAtom = atomWithReducer(0, reducer)
```

`countAtom.test.ts`:

```ts
import { renderHook, act } from '@testing-library/react-hooks'
import { useAtom } from 'jotai'
import { countAtom } from './countAtom'

test('should increment counter', () => {
  const { result } = renderHook(() => useAtom(countAtom))

  act(() => {
    result.current[1]('INCREASE')
  })

  expect(result.current[0]).toBe(1)
})
```

### Example with React-Native

Of course, you can test React-Native components too the same way, with or without `Provider`.

```tsx
import React from 'react'
import { render, fireEvent } from '@testing-library/react-native'
import { Counter } from './counter'

test('should increment counter', () => {
  // Arrange
  const { getByText } = render(<Counter />)
  const counter = getByText('0')
  const incrementButton = getByText('one up')
  // Act
  fireEvent.press(incrementButton)
  // Assert
  expect(counter.props.children.toString()).toEqual('1')
})
```

---

### Guides Typescript (`docs/guides/typescript.mdx`)

---
title: TypeScript
description: How to use Jotai with TypeScript
nav: 8.02
keywords: typescript,types
---

### Version requirement

Jotai requires TypeScript 5.5 or newer. Upgrade your TypeScript version if you're on 5.4 or older.

Jotai relies heavily on type inferences and requires `strictNullChecks` to be enabled. Consider adding `"strict": true` in your tsconfig.json.
[#550](https://github.com/pmndrs/jotai/issues/550)
[#802](https://github.com/pmndrs/jotai/issues/802)
[#838](https://github.com/pmndrs/jotai/issues/838)

### Notes

#### Primitive atoms are basically type inferred

```ts
const numAtom = atom(0) // primitive number atom
const strAtom = atom('') // primitive string atom
```

### Primitive atoms can be explicitly typed

```ts
const numAtom = atom<number>(0)
const numAtom = atom<number | null>(0)
const arrAtom = atom<string[]>([])
```

#### Derived atoms can mostly have their types inferred

In general, this is the recommended approach since typing derived
atoms can get a little confusing, particularly for those who are
doing it for the first time.

```ts

# Read only derived atoms
const readOnlyAtom = atom((get) => get(numAtom))
const asyncReadOnlyAtom = atom(async (get) => await get(someAsyncAtom))

# Write only atoms
const writeOnlyAtom = atom(null, (_get, set, str: string) => set(fooAtom, str))
const multipleArgumentsAtom = atom(
  null,
  (_get, set, valueOne: number, valueTwo: number) =>
    set(fooAtom, Math.max(valueOne, valueTwo))
);

# Read/Write atoms
const readWriteAtom = atom(
  (get) => get(strAtom),
  (_get, set, num: number) => set(strAtom, String(num))
)
const asyncReadWriteAtom = atom(
  async (get) => await get(asyncStrAtom),
  (_get, set, num: number) => set(strAtom, String(num))
)
```

#### Derived atoms can also be explicitly typed

If you encounter a situation where you need or want to explicitly
type your derived atoms, you can do that as well.

```ts
const asyncStrAtom = atom<Promise<string>>(async () => 'foo')

/**
 * For write only atoms you'll need to supply three type parameters.
 * The first type parameter describes the value returned from the atom. In the following example this is `null`.
 * The second type parameter describes the arguments (plural) you will pass to the "write" function. Even if you only
 * plan to have one argument, this type must be an array as show in the example.
 * The third type parameter describes the return value of the "write" function. Normally, there is no return value,
 * which is why we use `void` in the example below.
 */
const writeOnlyAtom = atom<null, [string, number], void>(
  null,
  (_get, set, stringValue, numberValue) => set(fooAtom, stringValue),
)

/**
 * Read/Write atoms also take the same three type parameters.
 * Just for the sake of completeness, in this example, we show that the first type parameter
 * can also describe an async atom.
 */
const readWriteAtom = atom<Promise<string>, [number], void>(
  async (get) => await get(asyncStrAtom),
  (_get, set, num) => set(strAtom, String(num)),
)
```

#### useAtom is typed based on atom types

```ts
const [num, setNum] = useAtom(primitiveNumAtom)
const [num] = useAtom(readOnlyNumAtom)
const [, setNum] = useAtom(writeOnlyNumAtom)
```

#### Access to the value type of an atom

```ts
import { ExtractAtomValue, useAtomValue } from 'jotai'
import { userAtom } from 'state'
import { useQuery } from '@tanstack/react-query'

export default function WriteReview(hid) {
  const user = useAtomValue(userAtom)
  const res = useGetReviewQuery(user)
}

function useGetReviewQuery(user: ExtractAtomValue<typeof userAtom>) {
  return fetch('/api/user/' + user.id + '/review')
}
```

---

### Guides Using Store Outside React (`docs/guides/using-store-outside-react.mdx`)

---
title: Using store outside React
description: Using store outside React
nav: 8.98
keywords: state, outside, react
published: false
---

Jotai's state resides in React, but sometimes it would be nice
to interact with the world outside React.

## createStore

[`createStore`](../core/store.mdx#createstore) provides a store interface that can be used to store your atoms. Using the store, you can access and mutate the state of your stored atoms from outside React.

```jsx
import { atom, useAtomValue, createStore, Provider } from 'jotai'

const timeAtom = atom(0)
const store = createStore()

store.set(timeAtom, (prev) => prev + 1) // Update atom's value
store.get(timeAtom) // Read atom's value

function Component() {
  const time = useAtomValue(timeAtom) // Inside React
  return (
    <div className="App">
      <h1>{time}</h1>
    </div>
  )
}

export default function App() {
  return (
    <Provider store={store}>
      <Component />
    </Provider>
  )
}
```

### Examples

<Stackblitz id="vitejs-vite-m1h61f" file="src%2FApp.tsx" />

---

### Guides Vite (`docs/guides/vite.mdx`)

---
title: Vite
description: How to use Jotai with Vite
nav: 8.99
keywords: vite
published: false
---

You can use the plugins from the `jotai-babel` package to enhance your developer experience when using Vite and Jotai.

In your `vite.config.ts`:

```js
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import babel from '@rolldown/plugin-babel'
import jotaiDebugLabel from 'jotai-babel/plugin-debug-label'
import jotaiReactRefresh from 'jotai-babel/plugin-react-refresh'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    react(),
    babel({
      plugins: [jotaiDebugLabel, jotaiReactRefresh],
    }),
  ],
  // ... The rest of your configuration
})
```

There's a template below to try it yourself.

### Examples

#### Vite Template

<Stackblitz id="vitejs-vite-xhhxve" file="vite.config.ts" />

---

### Guides Waku (`docs/guides/waku.mdx`)

---
title: Waku
description: How to use Jotai with Waku
nav: 8.04
keywords: waku
status: draft
---

### Hydration

Jotai has support for hydration of atoms with `useHydrateAtoms`. The documentation for the hook can be seen [here](../utils/ssr.mdx).

---

### Recipes Atom With Broadcast (`docs/recipes/atom-with-broadcast.mdx`)

---
title: atomWithBroadcast
nav: 9.09
keywords: creators,broadcast
---

> `atomWithBroadcast` creates an atom. The atom will be shared between
> browser tabs and frames, similar to `atomWithStorage` but with the
> initialization limitation.

This can be useful when you want states to interact with each other without the use of localStorage.
By using the BroadcastChannel API, you can enable basic communication between browsing contexts such as windows, tabs, frames, components, or iframes, and workers on the same origin.
According to the MDN documentation, receiving a message during initialization is not supported in the BroadcastChannel, but if you want to support that functionality, you may need to add extra option to atomWithBroadcast, such as local storage.

```tsx
import { atom, SetStateAction } from 'jotai'

export function atomWithBroadcast<Value>(key: string, initialValue: Value) {
  const baseAtom = atom(initialValue)
  const listeners = new Set<(event: MessageEvent<any>) => void>()
  const channel = new BroadcastChannel(key)

  channel.onmessage = (event) => {
    listeners.forEach((l) => l(event))
  }

  const broadcastAtom = atom(
    (get) => get(baseAtom),
    (get, set, update: { isEvent: boolean; value: SetStateAction<Value> }) => {
      set(baseAtom, update.value)

      if (!update.isEvent) {
        channel.postMessage(get(baseAtom))
      }
    },
  )

  broadcastAtom.onMount = (setAtom) => {
    const listener = (event: MessageEvent<any>) => {
      setAtom({ isEvent: true, value: event.data })
    }

    listeners.add(listener)

    return () => {
      listeners.delete(listener)
    }
  }

  const returnedAtom = atom(
    (get) => get(broadcastAtom),
    (_get, set, update: SetStateAction<Value>) => {
      set(broadcastAtom, { isEvent: false, value: update })
    },
  )

  return returnedAtom
}

const broadAtom = atomWithBroadcast('count', 0)

const ListOfThings = () => {
  const [count, setCount] = useAtom(broadAtom)

  return (
    <div>
      {count}
      <button onClick={() => setCount(count + 1)}>+1</button>
    </div>
  )
}
```

<Stackblitz id="vitejs-vite-imqbzg" file="src%2FApp.tsx" />

---

### Recipes Atom With Compare (`docs/recipes/atom-with-compare.mdx`)

---
title: atomWithCompare
nav: 9.05
keywords: creators,compare
---

> `atomWithCompare` creates atom that triggers updates when custom compare function `areEqual(prev, next)` is false.

This can help you avoid unwanted re-renders by ignoring state changes that don't matter to your application.

Note: Jotai uses `Object.is` internally to compare values when changes occur. If `areEqual(a, b)` returns false, but `Object.is(a, b)` returns true, Jotai will not trigger an update.

```ts
import { atomWithReducer } from 'jotai/utils'

export function atomWithCompare<Value>(
  initialValue: Value,
  areEqual: (prev: Value, next: Value) => boolean,
) {
  return atomWithReducer(initialValue, (prev: Value, next: Value) => {
    if (areEqual(prev, next)) {
      return prev
    }

    return next
  })
}
```

Here's how you'd use it to make an atom that ignores updates that are shallow-equal:

```ts
import { atomWithCompare } from 'XXX'
import { shallowEquals } from 'YYY'
import { CSSProperties } from 'react'

const styleAtom = atomWithCompare<CSSProperties>(
  { backgroundColor: 'blue' },
  shallowEquals,
)
```

In a component:

```jsx
const StylePreview = () => {
  const [styles, setStyles] = useAtom(styleAtom)

  return (
    <div>
      <div styles={styles}>Style preview</div>

      {/* Clicking this button twice will only trigger one render */}
      <button onClick={() => setStyles({ ...styles, backgroundColor: 'red' })}>
        Set background to red
      </button>

      {/* Clicking this button twice will only trigger one render */}
      <button onClick={() => setStyles({ ...styles, fontSize: 32 })}>
        Enlarge font
      </button>
    </div>
  )
}
```

---

### Recipes Atom With Debounce (`docs/recipes/atom-with-debounce.mdx`)

---
title: atomWithDebounce
nav: 9.10
keywords: creators,debounce
---

> `atomWithDebounce` helps with creating an atom where state set should be debounced.

This util is useful for text search inputs, where you would like to call **functions in derived atoms only once** after waiting for a duration, instead of firing an action on every keystroke.

```
/* Detailed source-code truncated for AI context efficiency. */
```

### Debouncing and async work

Clearing the timeout in `clearTimeoutAtom` cancels a scheduled publication to `debouncedValueAtom`, but it does not cancel async work that has already started.

For an async derived atom, pass its `options.signal` to `fetch` so the request can be aborted when that atom recalculates. If the atom reads only `debouncedValueAtom`, a new keystroke does not invalidate it immediately: the dependency changes when the debounced value is published (or a reset publishes it immediately). If a result should stop being eligible as soon as the text changes, track the current input separately from the debounced request value.

### Caveat

Please note that this atom has different objectives from concurrent features in React 18 such as `useTransition` and `useDeferredValue` whose main aim is to prevent blocking of interaction with the page for expensive updates.

For more info, please read this github discussion https://github.com/reactwg/react-18/discussions/41 under the section titled **"How is it different from setTimeout?"**

### Example Usage

The sandbox link below shows how we would use a derived atom to fetch state based on the value of `debouncedValueAtom`.

When typing a pokemon's name in `<SearchInput>`, we do not send a get request on every letter, but only after `delayMilliseconds` has passed since the last text input.

This reduces the number of backend requests to the server.

<Stackblitz id="vitejs-vite-chvvtu" file="src%2FApp.tsx" />

---

### Recipes Atom With Listeners (`docs/recipes/atom-with-listeners.mdx`)

---
title: atomWithListeners
nav: 9.08
keywords: creators,listeners
---

> `atomWithListeners` creates an atom and a hook. The hook can be called to
> add a new listener. The hook takes as an argument a callback, and that
> callback is called every time the atom's value is set. The hook also
> returns a function to remove the listener.

This can be useful when you want to create a component that can listen to when
an atom's state changes without having to re-render that component with each of
those state changes.

```ts
import { useEffect } from 'react'
import {
  atom,
  useAtom,
  useSetAtom,
  Getter,
  Setter,
  SetStateAction,
} from 'jotai'

type Callback<Value> = (
  get: Getter,
  set: Setter,
  newVal: Value,
  prevVal: Value,
) => void

export function atomWithListeners<Value>(initialValue: Value) {
  const baseAtom = atom(initialValue)
  const listenersAtom = atom<Callback<Value>[]>([])
  const anAtom = atom(
    (get) => get(baseAtom),
    (get, set, arg: SetStateAction<Value>) => {
      const prevVal = get(baseAtom)
      set(baseAtom, arg)
      const newVal = get(baseAtom)
      get(listenersAtom).forEach((callback) => {
        callback(get, set, newVal, prevVal)
      })
    },
  )
  const useListener = (callback: Callback<Value>) => {
    const setListeners = useSetAtom(listenersAtom)
    useEffect(() => {
      setListeners((prev) => [...prev, callback])
      return () =>
        setListeners((prev) => {
          const index = prev.indexOf(callback)
          return [...prev.slice(0, index), ...prev.slice(index + 1)]
        })
    }, [setListeners, callback])
  }
  return [anAtom, useListener] as const
}
```

In a component:

```jsx
const [countAtom, useCountListener] = atomWithListeners(0)

function EvenCounter() {
  const [evenCount, setEvenCount] = useAtom(countAtom)

  useCountListener(
    useCallback(
      (get, set, newVal, prevVal) => {
        // Every time `countAtom`'s value is set, we check if its new value
        // is even, and if it is, we increment `evenCount`.
        if (newVal % 2 === 0) {
          setEvenCount((c) => c + 1)
        }
      },
      [setEvenCount],
    ),
  )

  return <>Count was set to an even number {evenCount} times.</>
}
```

---

### Recipes Atom With Refresh And Default (`docs/recipes/atom-with-refresh-and-default.mdx`)

---
title: atomWithRefreshAndDefault
nav: 9.07
keywords: creators,refresh,default
---

> This is for another implementation of [atomWithDefault](../utilities/resettable.mdx#atomwithdefault)

### Look back to atomWithDefault behavior

As you can see in the example code in atomWithDefault section, the two atoms' relation is disconnected after updating created one, `count2Atom = atomWithDefault((get) => get(count1Atom) * 2)`.
Let's confirm what's occurred,

- 1. Click "increment count1", then count1 is 2 and count2 is 4
- 2. Click "increment count2", then count1 is 2 and count2 is 5 (Disconnected!!)

Those atoms have no relation after updating count2Atom. So,

- Click "increment count1", count1 is incremented only
- Even if you reset count2Atom, these dependency relation never come back

### Motivation

In some cases,

- After disconnecting and resetting, they should come back to their relation
- Derived atoms should be reset based on updated the original atom
- We'd like to reset all derived atoms but just want to operate as simply as possible

How do we make those cases?
Here is a declarative way to create a function to provide a refreshable atom instead of atomWithDefault.

```js
const refreshCountAtom = atom(0)

const baseDataAtom = atom(1) // original data, e.g. base count1Atom
const dataAtom = atom(
  (get) => {
    get(refreshCountAtom) // it's introduced at atomWithRefresh
    return get(baseDataAtom)
  },
  (get, set, update) => {
    set(baseDataAtom, update)
  },
)

const atomWithRefreshAndDefault = (refreshAtom, getDefault) => {
  const overwrittenAtom = atom(null)
  return atom(
    (get) => {
      const lastState = get(overwrittenAtom)
      if (lastState && lastState.refresh === get(refreshAtom)) {
        return lastState.value
      }
      return getDefault(get)
    },
    (get, set, update) => {
      set(overwrittenAtom, { refresh: get(refreshAtom), value: update })
    },
  )
}

// This is an alternative of `atomWithDefault((get) => get(count1Atom) * 2)`
const refreshableAtom = atomWithRefreshAndDefault(
  refreshCountAtom,
  (get) => get(dataAtom) * 2,
)

// You can reset by updating just one atom
const resetRootAtom = atom(null, (get, set) => {
  set(refreshCountAtom, get(refreshCountAtom) + 1)
})
```

<Stackblitz id="vitejs-vite-1m7ce3" file="src%2FApp.tsx" />

---

### Recipes Atom With Refresh (`docs/recipes/atom-with-refresh.mdx`)

---
title: atomWithRefresh
nav: 9.06
keywords: creators,refresh
---

`atomWithRefresh` has been provided by `jotai/utils` since v2.7.0.
[Jump to the doc](../utilities/resettable.mdx#atomwithrefresh)

---

### Recipes Atom With Toggle And Storage (`docs/recipes/atom-with-toggle-and-storage.mdx`)

---
title: atomWithToggleAndStorage
nav: 9.05
keywords: creators,storage
---

> `atomWithToggleAndStorage` is like `atomWithToggle` but also persist the state anytime it changes in given storage using [`atomWithStorage`](../utilities/storage.mdx).

Here is the source:

```ts
import { WritableAtom, atom } from 'jotai'
import { atomWithStorage } from 'jotai/utils'

export function atomWithToggleAndStorage(
  key: string,
  initialValue?: boolean,
  storage?: any,
): WritableAtom<boolean, [boolean?], void> {
  const anAtom = atomWithStorage(key, initialValue, storage)
  const derivedAtom = atom(
    (get) => get(anAtom),
    (get, set, nextValue?: boolean) => {
      const update = nextValue ?? !get(anAtom)
      void set(anAtom, update)
    },
  )

  return derivedAtom as WritableAtom<boolean, [boolean?], void>
}
```

And how it's used:

```js
import { atomWithToggleAndStorage } from 'XXX'

// will have an initial value set to false & get stored in localStorage under the key "isActive"
const isActiveAtom = atomWithToggleAndStorage('isActive')
```

The usage in a component is also the same as `atomWithToggle`.

---

### Recipes Atom With Toggle (`docs/recipes/atom-with-toggle.mdx`)

---
title: atomWithToggle
nav: 9.04
keywords: creators,toggle
---

> `atomWithToggle` creates a new atom with a boolean as initial state & a setter function to toggle it.

This avoids the boilerplate of having to set up another atom just to update the state of the first.

```ts
import { WritableAtom, atom } from 'jotai'

export function atomWithToggle(
  initialValue?: boolean,
): WritableAtom<boolean, [boolean?], void> {
  const anAtom = atom(initialValue, (get, set, nextValue?: boolean) => {
    const update = nextValue ?? !get(anAtom)
    set(anAtom, update)
  })

  return anAtom as WritableAtom<boolean, [boolean?], void>
}
```

An optional initial state can be provided as the first argument.

The setter function can have an optional argument to force a particular state, such as if you want to make a setActive function out of it.

Here is how it's used.

```js
import { atomWithToggle } from 'XXX'

// will have an initial value set to true
const isActiveAtom = atomWithToggle(true)
```

And in a component:

```jsx
const Toggle = () => {
  const [isActive, toggle] = useAtom(isActiveAtom)

  return (
    <>
      <button onClick={() => toggle()}>
        isActive: {isActive ? 'yes' : 'no'}
      </button>
      <button onClick={() => toggle(true)}>force true</button>
      <button onClick={() => toggle(false)}>force false</button>
    </>
  )
}
```

---

### Recipes Custom Useatom Hooks (`docs/recipes/custom-useatom-hooks.mdx`)

---
title: Custom useAtom hooks
nav: 9.02
keywords: custom,hook
---

This page shows the ways of creating different utility functions. Utility functions save your time on coding, and you can preserve your base atom for other usage.

### utils

#### useSelectAtom

```js
import { useAtomValue } from 'jotai'
import { selectAtom } from 'jotai/utils'

export function useSelectAtom(anAtom, selector) {
  const selectorAtom = selectAtom(
    anAtom,
    selector,
    // Alternatively, you can customize `equalityFn` to determine when it will rerender
    // Check selectAtom's signature for details.
  )
  return useAtomValue(selectorAtom)
}

// how to use it
function useN(n) {
  const selector = useCallback((v) => v[n], [n])
  return useSelectAtom(arrayAtom, selector)
}
```

Please note that in this case `keyFn` must be stable, either define outside render or wrap with `useCallback`.

#### useFreezeAtom

```js
import { useAtom } from 'jotai'
import { freezeAtom } from 'jotai/utils'

export function useFreezeAtom(anAtom) {
  return useAtom(freezeAtom(anAtom))
}
```

#### useSplitAtom

```js
import { useAtom } from 'jotai'
import { splitAtom } from 'jotai/utils'

export function useSplitAtom(anAtom) {
  return useAtom(splitAtom(anAtom))
}
```

### extensions

#### useFocusAtom

```js
import { useAtom } from 'jotai'
import { focusAtom } from 'jotai-optics'

/* if an atom is created here, please use `useMemo(() => atom(initValue), [initValue])` instead. */
export function useFocusAtom(anAtom, keyFn) {
    return useAtom(focusAtom(anAtom, keyFn))
}

// how to use it
useFocusAtom(anAtom) {
    useMemo(() => atom(initValue), [initValue]),
    useCallback((optic) => optic.prop('key'), [])
}
```

#### Stackblitz

<Stackblitz id="vitejs-vite-ge1mah" file="src%2FApp.tsx" />

Please note that in this case `keyFn` must be stable, either define outside render or wrap with `useCallback`.

---

### Recipes Large Objects (`docs/recipes/large-objects.mdx`)

---
title: Large objects
nav: 9.01
keywords: large,object
---

> The examples and descriptions below are based on this [codesandbox](https://codesandbox.io/s/zealous-sun-f2qnl?file=/src/App.tsx), so it will give you a better understanding if you check it out along with these examples.

Sometimes we have nested data we need to store in atoms, and we may need to change that data at different levels, or we need to use part of that data without listening to all changes.

Consider this example:

```js
const initialData = {
  people: [
    {
      name: 'Luke Skywalker',
      information: { height: 172 },
      siblings: ['John Skywalker', 'Doe Skywalker'],
    },
    {
      name: 'C-3PO',
      information: { height: 167 },
      siblings: ['John Doe', 'Doe John'],
    },
  ],
  films: [
    {
      title: 'A New Hope',
      planets: ['Tatooine', 'Alderaan'],
    },
    {
      title: 'The Empire Strikes Back',
      planets: ['Hoth'],
    },
  ],
  info: {
    tags: ['People', 'Films', 'Planets', 'Titles'],
  },
}
```

## focusAtom

> `focusAtom` creates a new atom, based on the focus that you pass to it. [jotai-optics](../extensions/optics.mdx#focusatom)

We use this utility to focus an atom and create an atom from a specific part of the data. For example we may need to consume the people property of the above data, Here's how we do it:

```js
import { atom } from 'jotai'
import { focusAtom } from 'jotai-optics'

const dataAtom = atom(initialData)

const peopleAtom = focusAtom(dataAtom, (optic) => optic.prop('people'))
```

`focusAtom` returns `WritableAtom` which means it's possible to change the `peopleAtom` data.

If we change the `films` property of the above data example, the `peopleAtom` won't cause a re-render, so that's one of the benefits of using `focusAtom`.

## splitAtom

> The `splitAtom` utility is useful when you want to get an atom for each element in a list. [jotai/utils](../utilities/split.mdx)

We use this utility for atoms that return arrays as their values. For example, the `peopleAtom` we made above returns the people property array, so we can return an atom for each item of that array. If the array atom is writable, `splitAtom` returned atoms are going to be writable, if the array atom is read-only, the returned atoms will be read-only too.

```js
import { splitAtom } from 'jotai/utils'

const peopleAtomsAtom = splitAtom(peopleAtom)
```

And this is how we use it in components.

```jsx
const People = () => {
  const [peopleAtoms] = useAtom(peopleAtomsAtom)
  return (
    <div>
      {peopleAtoms.map((personAtom) => (
        <Person personAtom={personAtom} key={`${personAtom}`} />
      ))}
    </div>
  )
}
```

## selectAtom

> This function creates a derived atom whose value is a function of the original atom's value. [jotai/utils](../utilities/select.mdx)

This utility is like `focusAtom`, but it always returns a read-only atom.

Assume we want to consume the info data, and its data is always unchangeable. We can make a read-only atom from it and select that created atom.

```js
// first we create a derived atom based on initialData.info
const infoAtom = atom((get) => get(dataAtom).info)
```

Then we use it in our component:

```jsx
import { atom, useAtom } from 'jotai'
import { selectAtom, splitAtom } from 'jotai/utils'

const tagsSelector = (s) => s.tags
const Tags = () => {
  const tagsAtom = selectAtom(infoAtom, tagsSelector)
  const tagsAtomsAtom = splitAtom(tagsAtom)
  const [tagAtoms] = useAtom(tagsAtomsAtom)
  return (
    <div>
      {tagAtoms.map((tagAtom) => (
        <Tag key={`${tagAtom}`} tagAtom={tagAtom} />
      ))}
    </div>
  )
}
```

---

### Recipes Use Atom Effect (`docs/recipes/use-atom-effect.mdx`)

---
title: useAtomEffect
nav: 9.03
keywords: effect, atom effect, side effect, side-effect, sideeffect, hook, useAtomEffect
---

> `useAtomEffect` runs side effects in response to changes in atoms or props using [atomEffect](../extensions/effect.mdx).

The effectFn reruns whenever the atoms it depends on change or the effectFn itself changes. Be sure to memoize the effectFn if it's a function defined in the component.

⚠️ Note: always prefer to use a [stable version of useMemo and useCallback](https://github.com/alexreardon/use-memo-one) to avoid extra atomEffect recomputations. You may rely on useMemo as a performance optimization, but not as a semantic guarantee. In the future, React may choose to “forget” some previously memoized values and recalculate them on next render, e.g. to free memory for offscreen components.

```ts
import { useMemoOne as useStableMemo } from 'use-memo-one'
import { useAtomValue } from 'jotai/react'
import { atomEffect } from 'jotai-effect'

type EffectFn = Parameters<typeof atomEffect>[0]

export function useAtomEffect(effectFn: EffectFn) {
  useAtomValue(useStableMemo(() => atomEffect(effectFn), [effectFn]))
}
```

### Example Usage

```tsx
import { useCallbackOne as useStableCallback } from 'use-memo-one'
import { atom, useAtom } from 'jotai'
import { atomFamily } from 'jotai/utils'
import { useAtomEffect } from './useAtomEffect'

const channelSubscriptionAtomFamily = atomFamily<Channel>(
  (channelId: string) => {
    return atom(new Channel(channelId))
  },
)
const messagesAtom = atom<Message[]>([])

function Messages({ channelId }: { channelId: string }) {
  const [messages] = useAtom(messagesAtom)
  useAtomEffect(
    useStableCallback(
      (get, set) => {
        const channel = get(channelSubscriptionAtomFamily(channelId))
        const unsubscribe = channel.subscribe((message) => {
          set(messagesAtom, (prev) => [...prev, message])
        })
        return unsubscribe
      },
      [channelId],
    ),
  )
  return (
    <>
      <h1>You have {messages.length} messages</h1>
      <hr />
      {messages.map((message) => (
        <div key={message.id}>{message.text}</div>
      ))}
    </>
  )
}
```

---

### Recipes Use Reducer Atom (`docs/recipes/use-reducer-atom.mdx`)

---
title: useReducerAtom
nav: 9.11
keywords: reducer, hook, useReducerAtom
---

`useReducerAtom` is a custom hook to apply a reducer to a primitive atom.

It's useful to change the update behavior temporarily.
Also, consider [atomWithReducer](../utilities/reducer.mdx)
for the atom-level solution.

```ts
import { useCallback } from 'react'
import { useAtom } from 'jotai'
import type { PrimitiveAtom } from 'jotai'

export function useReducerAtom<Value, Action>(
  anAtom: PrimitiveAtom<Value>,
  reducer: (v: Value, a: Action) => Value,
) {
  const [state, setState] = useAtom(anAtom)
  const dispatch = useCallback(
    (action: Action) => setState((prev) => reducer(prev, action)),
    [setState, reducer],
  )
  return [state, dispatch] as const
}
```

### Example Usage

```jsx
import { atom } from 'jotai'

const countReducer = (prev, action) => {
  if (action.type === 'inc') return prev + 1
  if (action.type === 'dec') return prev - 1
  throw new Error('unknown action type')
}

const countAtom = atom(0)

const Counter = () => {
  const [count, dispatch] = useReducerAtom(countAtom, countReducer)
  return (
    <div>
      {count}
      <button onClick={() => dispatch({ type: 'inc' })}>+1</button>
      <button onClick={() => dispatch({ type: 'dec' })}>-1</button>
    </div>
  )
}
```

<Stackblitz id="vitejs-vite-gsctj6" file="src%2FApp.tsx" />

---

### Third Party Bunja (`docs/third-party/bunja.mdx`)

---
title: Bunja
description: State Lifetime Manager
nav: 5.03
keywords: scope,di,raii,lifetime
---

[Bunja](https://github.com/disjukr/bunja) is lightweight State Lifetime Manager.

It provides an RAII wrapper for jōtai atoms.

---

See also:

- [Bunja README](https://github.com/disjukr/bunja/blob/main/README.md)
- [Presentations](https://github.com/disjukr/bunja/tree/main/presentations)

## install

```
npm install bunja
```

### Defining a Bunja

You can define a bunja using the `bunja` function.

When you access the defined bunja with the `useBunja` hook, a bunja instance is created.

If all components in the render tree that refer to the bunja disappear, the bunja instance is automatically destroyed.

If you want to trigger effects when the lifetime of a bunja starts and ends, you can use the `bunja.effect` function.

```ts
import { bunja } from 'bunja'
import { useBunja } from 'bunja/react'

const countBunja = bunja(() => {
  const countAtom = atom(0)

  bunja.effect(() => {
    console.log('mounted')
    return () => console.log('unmounted')
  })

  return { countAtom }
})

function MyComponent() {
  const { countAtom } = useBunja(countBunja)
  const [count, setCount] = useAtom(countAtom)
  // Your component logic here
}
```

#### Seeding the first instance

If a bunja needs creation-time data, use `bunja.withSeed`.
A default seed is required when the bunja is declared, so callers may still omit the seed.

The seed is used only when a matching bunja instance is first created.
It is not part of the bunja instance identity.
If the matching instance already exists, later seeds are ignored.

```ts
const formBunja = bunja.withSeed({ title: '' }, (seed) => {
  const titleAtom = atom(seed.title)
  return { titleAtom }
})

useBunja({ bunja: formBunja, seed: { title: 'Draft' } })
```

### Defining a Bunja that relies on other Bunja

If you want to manage a state with a broad lifetime and another state with a narrower lifetime, you can create a (narrower) bunja that depends on a (broader) bunja.

For example, you can think of a bunja that holds the page state and another bunja that holds the modal state.

The page state lives longer than the modal state, and the modal state should exist from the moment the modal opens until it closes.

In such a case, you can write the following code.

```tsx
const pageBunja = bunja(() => {
  const pageStateAtom = atom({})
  return { pageStateAtom }
})

const childBunja = bunja(() => {
  const { pageStateAtom } = bunja.use(pageBunja)
  const childStateAtom = atom((get) => ({
    ...get(pageStateAtom),
    child: 'state',
  }))
  return { childStateAtom }
})

const modalBunja = bunja(() => {
  const { pageStateAtom } = bunja.use(pageBunja)
  const modalStateAtom = atom((get) => ({
    ...get(pageStateAtom),
    modal: 'state',
  }))

  bunja.effect(() => {
    console.log('modal opened')
    return () => console.log('modal closed')
  })

  return { modalStateAtom }
})

function Page() {
  const [modalOpen, setModalOpen] = useState(false)
  return (
    <>
      <Child />
      {modalOpen && <Modal />}
    </>
  )
}

function Child() {
  const { childStateAtom } = useBunja(childBunja)
  const childState = useAtomValue(childStateAtom)
  // ...
}

function Modal() {
  const { modalStateAtom } = useBunja(modalBunja)
  const modalState = useAtomValue(modalStateAtom)
  // ...
}
```

Notice that `pageBunja` is not directly `useBunja`-ed.

When you `useBunja` either `childBunja` or `modalBunja`, since they depend on `pageBunja`, it has the same effect as if `pageBunja` were also `useBunja`-ed.

When the modal is unmounted, there are no longer any places using `useBunja(modalBunja)`, so the instance of `modalBunja` is automatically destroyed.

### Dependency injection using Scope

You can use a bunja for local state management.

When you specify a scope as a dependency of the bunja, separate bunja instances are created based on the values injected into the scope.

```ts
import { bunja, createScope } from 'bunja'

const UrlScope = createScope()

const fetchBunja = bunja(() => {
  const url = bunja.use(UrlScope)

  const queryAtom = atomWithQuery((get) => ({
    queryKey: [url],
    queryFn: async () => (await fetch(url)).json(),
  }))

  return { queryAtom }
})
```

#### Injecting dependencies via React context

If you bind a scope to a React context, bunjas that depend on the scope can retrieve values from the corresponding React context.

In the example below, there are two React instances (`<ChildComponent />`) that reference the same `fetchBunja`, but since each looks at a different context value, two separate bunja instances are also created.

```tsx
import { createContext } from 'react'
import { bunja, createScope } from 'bunja'
import { bindScope } from 'bunja/react'

const UrlContext = createContext('https://example.com/')
const UrlScope = createScope()
bindScope(UrlScope, UrlContext)

const fetchBunja = bunja(() => {
  const url = bunja.use(UrlScope)

  const queryAtom = atomWithQuery((get) => ({
    queryKey: [url],
    queryFn: async () => (await fetch(url)).json(),
  }))

  return { queryAtom }
})

function ParentComponent() {
  return (
    <>
      <UrlContext value="https://example.com/foo">
        <ChildComponent />
      </UrlContext>
      <UrlContext value="https://example.com/bar">
        <ChildComponent />
      </UrlContext>
    </>
  )
}

function ChildComponent() {
  const { queryAtom } = useBunja(fetchBunja)
  const { data, isPending, isError } = useAtomValue(queryAtom)
  // Your component logic here
}
```

You can use the `createScopeFromContext` function to handle both the creation of the scope and the binding to the context in one step.

```ts
import { createContext } from 'react'
import { createScopeFromContext } from 'bunja/react'

const UrlContext = createContext('https://example.com/')
const UrlScope = createScopeFromContext(UrlContext)
```

#### Injecting dependencies directly into the scope

You might want to use a bunja directly within a React component where the values to be injected into the scope are created.

In such cases, you can use the second parameter of `useBunja` hook to inject values into the scope without wrapping the context separately.

```tsx
function MyComponent() {
  const { queryAtom } = useBunja(fetchBunja, [
    UrlScope.bind('https://example.com/'),
  ])
  const { data, isPending, isError } = useAtomValue(queryAtom)
  // Your component logic here
}
```

##### Doing the same thing inside a bunja

You can pass scope value pairs as the second argument to `bunja.use` to override scope values from within a bunja initialization function.

```ts
const myBunja = bunja(() => {
  const fooData = bunja.use(fetchBunja, [
    UrlScope.bind('https://example.com/foo'),
  ])
  const barData = bunja.use(fetchBunja, [
    UrlScope.bind('https://example.com/bar'),
  ])

  return { fooData, barData }
})
```

---

### Third Party Eager (`docs/third-party/eager.mdx`)

---
title: Eager
description: This doc describes Eager extension.
nav: 5.01
keywords: eager,derive,derived,async,zalgo,suspense,promise,react
---

**Jōtai Eager** provides primitives for building asynchronous data graphs that act on values as soon as they are available (either awaiting for them, or acting on them synchronously).

---

<CodeSandbox id="jotai-eager-example-pf38dg" />

### When is this useful?

- When local updates to the cache cause micro-suspensions
- When unnecessary recomputation causes performance issues

### Install

```sh
npm install jotai-eager
```

## Motivation

Jōtai offers powerful primitives for working with asynchronous data outside of the web framework (e.g. React), and allows the UI and business logic to properly integrate with the data layer. Many data-fetching integrations offer a peek into the client-side cache via atoms. When the cache is not yet populated, the atom has to resolve to a Promise of the value. However, if the value already exists in cache, and we do an optimistic update, then the value can be made available downstream immediately.

Building data graphs with these dual-natured (sometimes async, sometimes sync) atoms as a base can lead to unnecessary rerenders, stale values and micro-suspensions (in case of React) if not handled with care.

## Eager atoms

Let's say we have an atom that fetches names of pets from an API, and a filter atom:

```ts
const petsAtom = atom<Promise<string[]>>(...);
const filterAtom = atom('cat');
```

To create an atom of filtered pets using vanilla atoms, we would do the following:

```ts
const filteredPetsAtom = atom(async (get) => {
  const filter = get(filterAtom)
  const pets = await get(petsAtom)
  return pets.filter((name) => name.includes(filter))
}) // => Atom<Promise<string[]>>
```

`filteredPetsAtom` always returns a promise, even though the result
could be computed eagerly if the `filterAtom` was
the only changed dependency. We can fix that with **jotai-eager**:

```ts
import { eagerAtom } from 'jotai-eager'

const filteredPetsAtom = eagerAtom((get) => {
  const filter = get(filterAtom)
  const pets = get(petsAtom) // ✨ no await ✨
  return pets.filter((name) => name.includes(filter))
}) // => Atom<Promise<string[]> | string[]>
```

Now, the type reflects the eager behavior of this atom.
Its value will be `string[]` if the only thing that
changed is the filter, and `Promise<string[]>` otherwise!

## Avoiding request waterfalls

If your atom has multiple async dependencies, it's best to initiate all of them simultaneously and wait for their results, instead of awaiting them sequentially. In vanilla async atoms, `Promise.all(...)` is the API to use, but in eager atoms, use the `get.all()` API:

```ts
const myMessages = eagerAtom((get) => {
  const [user, messages] = get.all([userAtom, messagesAtom])
  return messages.filter((msg) => msg.authorId === user.id)
}) // => Atom<Message[] | Promise<Message[]>>
```

## Awaiting a Promise that is not another atom's value

We can use the `get.await` API to await regular Promises inside `eagerAtom` definitions, as long as we make sure that the Promise
we're passing is consistent across invocations of the atom's read function.

```ts
const statusAtom = eagerAtom((get) => {
  const statusPromise = get(currentInvoiceAtom).getStatus() // => Promise<InvoiceStatus>
  const status = get.await(statusPromise)
  //    ^? InvoiceStatus
  return status
})
```

## Handling Loading States with `loadable`

The `loadable` API wraps an atom to provide a consistent loading state representation, sharing a Promise cache between all jotai-eager APIs to minimize suspensions.

```ts
import { atom } from 'jotai';
import { loadable } from 'jotai-eager';

const asyncAtom = atom(async () => 'data');
const loadableAtom = loadable(asyncAtom);

// Use in component:
const state = useAtom(loadableAtom);
if (state.state === 'loading') return <div>Loading...</div>;
if (state.state === 'hasError') return <div>Error: {state.error}</div>;
return <div>{state.data}</div>;
```

## Handling Pending States with `withPending`

The `withPending` API wraps an atom to handle unresolved values by returning a fallback, providing an alternative to Jotai's `unwrap` with enhanced pending state management.

```ts
import { atom } from 'jotai'
import { withPending } from 'jotai-eager'

const asyncAtom = atom(Promise.resolve('data'))
const wrappedAtom = withPending(asyncAtom, () => 'Loading...')

// Returns 'Loading...' while pending, then 'data'
```

## Using `try` & `catch` inside eager atoms

Eager atoms internally use exceptions to suspend computation of the atom until an async dependency is fulfilled (similar to React's suspense behavior, but does not require React to function). This means that using exception handling inside eager atoms has to be instrumented with an additional call to `isEagerError`.

```ts
import { eagerAtom, isEagerError } from 'jotai-eager'

const fooAtom = eagerAtom((get) => {
  try {
    // ...
  } catch (e) {
    if (isEagerError(e)) {
      // Rethrow the error to be handled by `jotai-eager`
      throw e
    }

    // ...
  }
})
```

## Awaiting a Promise that is created inside the atom

Since the read function is 'retried' after a Promise we await is fulfilled, the mechanism expects
the same promise to be passed into `get.await` the second time around. Since we are creating the
Promise inside of the read function itself, that will never be the case, and we'll be stuck in an infinite loop.

```ts
const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms))

// This atom will be stuck in an infinite loop :(
const deferredNumberAtom = eagerAtom((get) => {
  get.await(sleep(1000)) // Waiting for a second...
  return 123
})
```

For this particular use case, since we're always deferring, using an `eagerAtom` over
a vanilla async atom is unnecessary.

## soon / soonAll

For more advanced usage, for example **conditional dependencies**, the `soon` and `soonAll` functions
can be used to perform sync/async transformations on data eagerly, on a more fine-grained level.

### Conditional dependency

```ts
import { soon } from 'jotai-eager'

// Given the following definitions:
//   const queryAtom: Atom<RestrictedItem | Promise<RestrictedItem>>;
//   const isAdminAtom: Atom<boolean | Promise<boolean>>;

// Atom<RestrictedItem | null | Promise<RestrictedItem | null>>
const restrictedItemAtom = atom((get) => {
  const isAdmin = get(isAdminAtom)
  return soon(isAdmin, (isAdmin) => (isAdmin ? get(queryAtom) : null))
})
```

### Conditional dependency (multiple conditions)

```ts
import { soon, soonAll } from 'jotai-eager'

// Given the following definitions:
//   const queryAtom: Atom<RestrictedItem | Promise<RestrictedItem>>;
//   const isAdminAtom: Atom<boolean | Promise<boolean>>;
//   const enabledAtom: Atom<boolean | Promise<boolean>>;

// Atom<RestrictedItem | null | Promise<RestrictedItem | null>>
const restrictedItemAtom = atom((get) => {
  return soon(
    soonAll(get(isAdminAtom), get(enabledAtom)),
    ([isAdmin, enabled]) => (isAdmin && enabled ? get(queryAtom) : null),
  )
})
```

---

### Third Party History (`docs/third-party/history.mdx`)

---
title: History
description: A Jōtai utility package for state history
nav: 4.04
keywords: history, undo, redo, track changes
---

[jotai-history](https://github.com/jotaijs/jotai-history) is a utility package for tracking state history in Jotai.

## Installation

```
npm install jotai-history
```

## `withHistory`

```js
import { withHistory } from 'jotai-history'

const targetAtom = atom(0)
const limit = 2
const historyAtom = withHistory(targetAtom, limit)

function Component() {
  const [current, previous] = useAtomValue(historyAtom)
  ...
}
```

### Description

`withHistory` creates an atom that tracks the history of states for a given `targetAtom`. The most recent `limit` states are retained.

### Action Symbols

- **RESET**  
  Clears the entire history, removing all previous states (including the undo/redo stack).

  ```js
  import { RESET } from 'jotai-history'

  ...

  function Component() {
    const setHistoryAtom = useSetAtom(historyAtom)
    ...
    setHistoryAtom(RESET)
  }
  ```

- **UNDO** and **REDO**  
  Moves the `targetAtom` backward or forward in its history.

  ```js
  import { REDO, UNDO } from 'jotai-history'

  ...

  function Component() {
    const setHistoryAtom = useSetAtom(historyAtom)
    ...
    setHistoryAtom(UNDO)
    setHistoryAtom(REDO)
  }
  ```

### Indicators

- **canUndo** and **canRedo**  
  Booleans indicating whether undo or redo actions are currently possible. These can be used to disable buttons or conditionally trigger actions.

  ```jsx
  ...

  function Component() {
    const history = useAtomValue(historyAtom)

    return (
      <>
        <button disabled={!history.canUndo}>Undo</button>
        <button disabled={!history.canRedo}>Redo</button>
      </>
    )
  }
  ```

<CodeSandbox id="g6qj3q" />

## Memory Management

> Because `withHistory` maintains a list of previous states, be mindful of memory usage by setting a reasonable `limit`. Applications that update state frequently can grow significantly in memory usage.

---

### Tools Babel (`docs/tools/babel.mdx`)

---
title: Babel
description: This doc describes the `jotai-babel` package.
nav: 6.02
keywords: babel,gatsby,fast,refresh
---

> **Deprecated**: `jotai/babel` bundle is deprecated and will be removed in v3. Please use the [`jotai-babel`](https://github.com/jotaijs/jotai-babel) package instead.

## jotai-babel/plugin-react-refresh

This plugin adds support for React Refresh for Jotai atoms. This makes sure that state isn't reset, when developing using React Refresh.

### Usage

With a `babel` configuration file:

```json
{
  "plugins": ["jotai-babel/plugin-react-refresh"]
}
```

The plugin recognizes a predefined list of atom function names (e.g. 'atom', 'atomFamily', 'atomWithDefault'). If you're using custom atom function names, you can explicitly supply them to ensure they are recognized.

Here's how you can configure it in your Babel setup:

```json
{
  "plugins": [
    ["jotai-babel/plugin-react-refresh", { "customAtomNames": ["customAtom"] }]
  ]
}
```

Examples can be found below.

## jotai-babel/plugin-debug-label

Jotai is based on object references and not keys (like Recoil). This means there's no identifier for atoms. To identify atoms, it's possible to add a `debugLabel` to an atom, which can be found in React devtools.

However, this can quickly become cumbersome to add a `debugLabel` to every atom.

This `babel` plugin adds a `debugLabel` to every atom, based on its identifier.

The plugin transforms this code:

```js
export const countAtom = atom(0)
```

Into:

```js
export const countAtom = atom(0)
countAtom.debugLabel = 'countAtom'
```

Default exports are also handled, based on the file naming:

```js
// countAtom.ts
export default atom(0)
```

Which transform into:

```js
// countAtom.ts
const countAtom = atom(0)
countAtom.debugLabel = 'countAtom'
export default countAtom
```

### Usage

It is recommended to disable this plugin for production builds to avoid unnecessary overhead. You can conditionally include it in your Babel configuration based on the environment.

With a `babel` configuration file:

```json
{
  "plugins": ["jotai-babel/plugin-debug-label"]
}
```

The plugin recognizes a predefined list of atom function names (e.g. 'atom', 'atomFamily', 'atomWithDefault'). If you're using custom atom function names, you can explicitly supply them to ensure they are recognized.

Here's how you can configure it in your Babel setup:

```json
{
  "plugins": [
    ["jotai-babel/plugin-debug-label", { "customAtomNames": ["customAtom"] }]
  ]
}
```

Examples can be found below.

## jotai-babel/preset

Jotai ships with a `babel preset` containing the plugins created for Jotai.

### Usage

With a `babel` configuration file:

```json
{
  "presets": ["jotai-babel/preset"]
}
```

You can also supply your atom names to the preset:

```json
{
  "presets": [["jotai-babel/preset", { "customAtomNames": ["customAtom"] }]]
}
```

### Examples

#### Next.js

<CodeSandbox id="o2di2" />

#### Parcel

<CodeSandbox id="bgf3b" />

---

### Tools Devtools (`docs/tools/devtools.mdx`)

---
title: Devtools
description: This doc describes Devtools for Jotai.
nav: 6.04
keywords: devtools,debug,snapshot
---

### Install

Install `jotai-devtools` to your project to get started.

```sh
npm install jotai-devtools
```

### Notes

- `<DevTools/>` is optimized to be tree-shakable for production builds, and **only works in a non-production environment**
- Hooks are dev-only, and are designed to work in a non-production environment
- Feedback welcome, please file issues or ask questions on the [Jotai DevTools GitHub Repo](https://github.com/jotaijs/jotai-devtools/discussions)

### Quick links

- [UI Devtools](#ui-devtools)
- Hooks
  - [useAtomsDebugValue](#useatomsdebugvalue)
  - [useAtomDevtools](#useatomdevtools)
  - [useAtomsDevtools](#useatomsdevtools)
  - [useAtomsSnapshot](#useatomssnapshot)
  - [useGotoAtomsSnapshot](#usegotoatomssnapshot)
- Migration guides
  - [Migrate from `@emotion/react`](https://github.com/jotaijs/jotai-devtools?tab=readme-ov-file#migrate-%C6%92rom-emotionreact-to-native-css)

### UI DevTools

Enhance your development experience with the UI based Jotai DevTool.

#### Babel plugin setup - (_Optional but highly recommended_)

Use [`jotai-babel`](https://github.com/jotaijs/jotai-babel) plugins for optimal debugging experience. Find the complete guide on the [babel](../tools/babel) page and/or [swc](../tools/swc) page.

```
npm install -D jotai-babel
```

```ts
{
  "presets": [
    // The preset includes two plugins:
    // - jotai-babel/plugin-react-refresh to enable hot reload for atoms
    // - jotai-babel/plugin-debug-label to automatically adds debug labels to atoms
    'jotai-babel/preset'
  ]
}
```

Example for Vite + React project:

```ts
// vite.config.ts

export default defineConfig({
  plugins: [
    react({
      babel: {
        presets: ['jotai-babel/preset'],
      },
    }),
  ],
})
```

If you are using Vite 8, first install these additional packages:

```
npm install -D @rolldown/plugin-babel @babel/core
```

Then use the following example instead:

```
// vite.config.ts
import babel from '@rolldown/plugin-babel';

export default defineConfig({
  plugins: [
    react(),
    babel({
      presets: ['jotai-babel/preset'],
    })
  ],
})
```

### Next JS setup

_You may skip this section if you're not using [Next.js](https://nextjs.org)._

Enable `transpilePackages` for the UI CSS and components to be transpiled correctly.

```ts
// next.config.ts
const nextConfig = {
  // Learn more here - https://nextjs.org/docs/advanced-features/compiler#module-transpilation
  // Required for UI css to be transpiled correctly 👇
  transpilePackages: ['jotai-devtools'],
}
module.exports = nextConfig
```

### Available props

```ts
type DevToolsProps = {
  // defaults to false
  isInitialOpen?: boolean
  // pass a custom store
  store?: Store
  // Defaults to light
  theme?: 'dark' | 'light'
  // Set the position of the trigger button
  // Defaults to `bottom-left`
  position?: 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left'
  // Custom nonce to allowlist jotai-devtools specific inline styles via CSP
  nonce?: string
  options?: {
    // Private atoms are used internally in atom creators like `atomWithStorage`
    // or `atomWithLocation`, etc. to manage the internal state.
    // Defaults to `false`
    shouldShowPrivateAtoms?: boolean
    // Expands the JSON tree view on initial render on Atom Viewer tab, Timeline tab, etc.
    // Defaults to `false`
    shouldExpandJsonTreeViewInitially?: boolean
    // The interval (in milliseconds) between each step of the time travel playback.
    // Defaults to `750ms`
    timeTravelPlaybackInterval?: number
    // The maximum number of snapshots to keep in the history.
    // The higher the number the more memory it will consume.
    // Defaults to `Infinity`. Recommended: `~30`
    snapshotHistoryLimit?: number
  }
}
```

### Usage

#### Provider-less

```tsx
import { DevTools } from 'jotai-devtools'
import 'jotai-devtools/styles.css'

const App = () => {
  return (
    <>
      <DevTools />
      {/* your app */}
    </>
  )
}
```

#### With Provider

```tsx
import { createStore } from 'jotai'
import { DevTools } from 'jotai-devtools'
import 'jotai-devtools/styles.css'

const customStore = createStore()

const App = () => {
  return (
    <Provider store={customStore}>
      <DevTools store={customStore} />
      {/* your app */}
    </Provider>
  )
}
```

### Preview

<Stackblitz id="vitejs-vite-hzldhk" file="src%2FApp.tsx" />

## useAtomsDebugValue

`useAtomsDebugValue` is a React hook that will show all atom values in React Devtools.

```ts
function useAtomsDebugValue(options?: {
  store?: Store
  enabled?: boolean
}): void
```

Internally, it uses `useDebugValue` which is only effective in DEV mode.
It will catch all atoms that are accessible from the place the hook is located.

### Example

```jsx
import { useAtomsDebugValue } from 'jotai-devtools/utils'

const textAtom = atom('hello')
textAtom.debugLabel = 'textAtom'

const lenAtom = atom((get) => get(textAtom).length)
lenAtom.debugLabel = 'lenAtom'

const TextBox = () => {
  const [text, setText] = useAtom(textAtom)
  const [len] = useAtom(lenAtom)
  return (
    <span>
      <input value={text} onChange={(e) => setText(e.target.value)} />({len})
    </span>
  )
}

const DebugAtoms = () => {
  useAtomsDebugValue()
  return null
}

const App = () => (
  <Provider>
    <DebugAtoms />
    <TextBox />
  </Provider>
)
```

<Stackblitz id="vitejs-vite-dmts5e" file="src%2FApp.tsx" />

## useAtomDevtools

`useAtomDevtools` is a React hook that manages ReduxDevTools extension for a particular atom.

```ts
function useAtomDevtools<Value>(
  anAtom: WritableAtom<Value, Value>,
  options?: {
    store?: Store
    name?: string
    enabled?: boolean
  },
): void
```

The `useAtomDevtools` hook accepts a generic type parameter (mirroring the type stored in the atom). Additionally, the hook accepts two invocation parameters, `anAtom` and `name`.
`anAtom` is the atom that will be attached to the devtools instance. `name` is an optional parameter that defines the debug label for the devtools instance. If `name` is undefined, `atom.debugLabel` will be used instead.

### Example

```ts
import { useAtomDevtools } from 'jotai-devtools/utils'

// The interface for the type stored in the atom.
export interface Task {
  label: string
  complete: boolean
}

// The atom to debug.
export const tasksAtom = atom<Task[]>([])

// If the useAtomDevtools name parameter is undefined, this value will be used instead.
tasksAtom.debugLabel = 'Tasks'

export const useTasksDevtools = () => {
  // The hook can be called simply by passing an atom for debugging.
  useAtomDevtools(tasksAtom)

  // Specify a custom type parameter
  useAtomDevtools<Task[]>(tasksAtom)

  // You can attach two devtools instances to the same atom and differentiate them with custom names.
  useAtomDevtools(tasksAtom, 'Tasks (Instance 1)')
  useAtomDevtools(tasksAtom, 'Tasks (Instance 2)')
}
```

## useAtomsDevtools

⚠️ Note: This hook is experimental (feedbacks are welcome) and only works in a `process.env.NODE_ENV !== 'production'` environment.

`useAtomsDevtools` is a catch-all version of `useAtomDevtools` where it shows all atoms in the store instead of showing a specific one.

```ts
function useAtomsDevtools(
  name: string,
  options?: {
    store?: Store
    enabled?: boolean
  },
): void
```

It takes a `name` parameter that is needed for naming the Redux devtools instance and a `store` parameter.

As a limitation for this API, we need to put `useAtomsDevtools` in a component where the consumed atoms should be in a lower place of the React tree than that component (`AtomsDevtools` in the below example).
`AtomsDevtools` component can be considered as a best practice for our apps.

### Example

```jsx
const countAtom = atom(0);
const doubleCountAtom = atom((get) => get(countAtom) * 2);

function Counter() {
  const  [count, setCount] =  useAtom(countAtom);
  const  [doubleCount] =  useAtom(doubleCountAtom);

  ...
}

const AtomsDevtools = ({ children }) => {
  useAtomsDevtools('demo')
  return children
}

export default function App()  {
  return (
    <AtomsDevtools>
      <Counter />
    </AtomsDevtools>
  )
 }
```

<Stackblitz id="vitejs-vite-lpr5rs" file="src%2FApp.tsx" />

## useAtomsSnapshot

⚠️ Note: This hook only works in a `process.env.NODE_ENV !== 'production'` environment. And it returns a static empty value in production.

`useAtomsSnapshot` takes a snapshot of the currently mounted atoms and their state.

```ts
function useAtomsSnapshot(options?: { store?: Store }): AtomsSnapshot
```

It accepts a `store` parameter and will return an `AtomsSnapshot`, which is basically a `Map<AnyAtom, unknown>`. You can use the `Map` API to iterate over atoms and their state.
This hook is primarily meant for debugging and devtools use cases.

Be careful using this hook because it will cause the component to re-render for all state changes.

### Example

```jsx
import { Provider } from 'jotai'
import { useAtomsSnapshot } from 'jotai-devtools/utils'

const RegisteredAtoms = () => {
  const atoms = useAtomsSnapshot()

  return (
    <div>
      <p>Atom count: {atoms.size}</p>
      <div>
        {Array.from(atoms).map(([atom, atomValue]) => (
          <p key={`${atom}`}>{`${atom.debugLabel}: ${atomValue}`}</p>
        ))}
      </div>
    </div>
  )
}

const App = () => (
  <Provider>
    <RegisteredAtoms />
  </Provider>
)
```

## useGotoAtomsSnapshot

⚠️ Note: This hook only works in a `process.env.NODE_ENV !== 'production'` environment. And it works like an empty function in the production environment.

`useGotoAtomsSnapshot` will update the current Jotai state to match the passed snapshot.

```ts
function useGotoAtomsSnapshot(options?: {
  store?: Store
}): (values: Iterable<readonly [AnyAtom, unknown]>) => void
```

This hook returns a callback, which takes a `snapshot` from the `useAtomsSnapshot` hook and will update the Jotai state. It accepts a `store` parameter.
This hook is primarily meant for debugging and devtools use cases.

### Example

```jsx
import { Provider } from 'jotai'
import { useAtomsSnapshot, useGotoAtomsSnapshot } from 'jotai-devtools/utils'

const petAtom = atom('cat')
const colorAtom = atom('blue')

const UpdateSnapshot = () => {
  const snapshot = useAtomsSnapshot()
  const goToSnapshot = useGotoAtomsSnapshot()
  return (
    <button
      onClick={() => {
        const newSnapshot = new Map(snapshot)
        newSnapshot.set(petAtom, 'dog')
        newSnapshot.set(colorAtom, 'green')
        goToSnapshot(newSnapshot)
      }}
    >
      Go to snapshot
    </button>
  )
}
```

---

### Tools Rolldown (`docs/tools/rolldown.mdx`)

---
title: Rolldown
description: This doc describes the `jotai-rolldown` package.
nav: 6.03
keywords: rolldown,vite,fast,refresh
---

⚠️ Note: This plugin is experimental. Feedback is welcome in the [Github repo](https://github.com/jotaijs/jotai-rolldown). Please file issues in the separate repo instead of `jotai` repo.

## jotaijs/jotai-rolldown

This plugin improves the development experience for Jotai by adding React Refresh support and adding devtools support.

### Usage

Install it with:

```sh
npm install --save-dev jotai-rolldown
```

You can add the plugin to `rolldown.config.ts`:

```ts
import jotai from 'jotai-rolldown'
import { defineConfig } from 'rolldown'

export default defineConfig({
  plugins: [jotai()],
})
```

or you can add the plugin to `vite.config.ts`:

```ts
import jotai from 'jotai-rolldown'
import { defineConfig } from 'vite'

export default defineConfig({
  plugins: [jotai()],
})
```

### Options

#### `reactRefresh`

Type: `boolean`
Default: `true` (in development)

Enables React Refresh support.

This makes sure that state isn't reset, when developing using React Refresh.

#### `debugLabel`

Type: `boolean`
Default: `true` (in development)

Jotai is based on object references and not keys (like Recoil). This means there's no identifier for atoms. To identify atoms, it's possible to add a `debugLabel` to an atom, which can be found in React devtools.
However, this can quickly become cumbersome to add a `debugLabel` to every atom.
This plugin adds a `debugLabel` to every atom, based on its identifier.

The plugin transforms this code:

```js
export const countAtom = atom(0)
```

Into:

```js
export const countAtom = atom(0)
countAtom.debugLabel = 'countAtom'
```

Default exports are also handled, based on the file naming:

```js
// countAtom.ts
export default atom(0)
```

Which transform into:

```js
// countAtom.ts
const countAtom = atom(0)
countAtom.debugLabel = 'countAtom'
export default countAtom
```

#### `atomNames`

Type: `string[]`
Default: `[]`

Custom atom function names so that the plugins can recognize them.

---

### Tools Skill (`docs/tools/skill.mdx`)

---
title: Skill
description: This doc describes the Jotai skill.
nav: 6.05
keywords: ai,agent,codex,claude,skill,skills
---

The skill helps coding agents write and review atom-based code. It can guide
atom design, derived atoms, write-only action atoms, async atoms, Provider/store
usage, render performance, TypeScript, tests, utilities, and extensions.

⚠️ Note: Feedback is welcome in the [Github repo](https://github.com/jotaijs/jotai-skills). Please file issues in the separate repo instead of `jotai` repo.

### Install

Install it with:

```sh
npx skills add jotaijs/jotai-skills --skill jotai
```

Install it to a specific coding agent:

```sh
npx skills add jotaijs/jotai-skills --skill jotai --agent codex
npx skills add jotaijs/jotai-skills --skill jotai --agent claude-code
```

Install it globally:

```sh
npx skills add jotaijs/jotai-skills --skill jotai --global
```

### Usage

After installing, ask a Jotai-related question:

```
Review the form atom design.
```

```
Refactor React Context state into atoms.
```

```
Reduce unrelated atom rerenders.
```

---

### Tools Swc (`docs/tools/swc.mdx`)

---
title: SWC
description: This doc describes SWC plugins for Jotai.
nav: 6.01
keywords: swc,next,nextjs,fast,refresh
---

⚠️ Note: These plugins are experimental. Feedback is welcome in the [Github repo](https://github.com/pmndrs/swc-jotai). Please file issues in the separate repo instead of `jotai` repo.

## @swc-jotai/react-refresh

This plugin adds support for React Refresh for Jotai atoms. This makes sure that state isn't reset, when developing using React Refresh.

### Usage

Install it with:

```sh
npm install --save-dev @swc-jotai/react-refresh
```

You can add the plugin to `.swcrc`:

```json
{
  "jsc": {
    "experimental": {
      "plugins": [["@swc-jotai/react-refresh", {}]]
    }
  }
}
```

You can use the plugin with the [experimental SWC plugins feature](https://nextjs.org/docs/advanced-features/compiler#swc-plugins-experimental) in Next.js.

```js
module.exports = {
  experimental: {
    swcPlugins: [['@swc-jotai/react-refresh', {}]],
  },
}
```

Examples can be found below.

## @swc-jotai/debug-label

Jotai is based on object references and not keys (like Recoil). This means there's no identifier for atoms. To identify atoms, it's possible to add a `debugLabel` to an atom, which can be found in React devtools.

However, this can quickly become cumbersome to add a `debugLabel` to every atom.

This `SWC` plugin adds a `debugLabel` to every atom, based on its identifier.

The plugin transforms this code:

```js
export const countAtom = atom(0)
```

Into:

```js
export const countAtom = atom(0)
countAtom.debugLabel = 'countAtom'
```

Default exports are also handled, based on the file naming:

```js
// countAtom.ts
export default atom(0)
```

Which transform into:

```js
// countAtom.ts
const countAtom = atom(0)
countAtom.debugLabel = 'countAtom'
export default countAtom
```

### Usage

Install it with:

```sh
npm install --save-dev @swc-jotai/debug-label
```

You can add the plugin to `.swcrc`:

```json
{
  "jsc": {
    "experimental": {
      "plugins": [["@swc-jotai/debug-label", {}]]
    }
  }
}
```

Or you can use the plugin with the [experimental SWC plugins feature](https://nextjs.org/docs/advanced-features/compiler#swc-plugins-experimental) in Next.js.

```js
module.exports = {
  experimental: {
    swcPlugins: [['@swc-jotai/debug-label', {}]],
  },
}
```

Examples can be found below.

### Custom atom names

You can enable the plugins for your custom atoms. You can supply them to the plugins like below:

```js
module.exports = {
  experimental: {
    swcPlugins: [
      ['@swc-jotai/debug-label', { atomNames: ['customAtom'] }],
      ['@swc-jotai/react-refresh', { atomNames: ['customAtom'] }],
    ],
  },
}
```

### Examples

### Next.js

<Stackblitz id="stackblitz-starters-ha5txx" file="app%2Fpage.tsx" />

---

### Utilities Async (`docs/utilities/async.mdx`)

---
title: Async
nav: 3.03
keywords: load,loadable,observable
---

All atoms support async behavior such as async read or async write. However there are APIs for more control described here.

## loadable

> In Jotai v3, `loadable` is no longer part of the core package.
> See the [v3 migration guide](../guides/migrating-to-v3.mdx#loadable-util)
> for a userland replacement built on `unwrap`.
> Alternatively, [`useAtomValueRaw`](../core/use-atom.mdx#useatomvalueraw) and
> [`useAtomValueRawSync`](../core/use-atom.mdx#useatomvaluerawsync) let you
> read an async atom's value without suspending.

If you don't want async atoms to suspend or throw to an error boundary (for example, for finer-grained control of loading and error logic), you can use the `loadable` util.

It would work the same way for any atom. Simply wrap your atoms with the `loadable` util. It returns a value with one of three states: `loading`, `hasData` and `hasError`.

```ts
{
	state: 'loading' | 'hasData' | 'hasError',
	data?: any,
	error?: any,
}
```

```jsx
import { loadable } from "jotai/utils"

const asyncAtom = atom(async (get) => ...)
const loadableAtom = loadable(asyncAtom)
// Does not need to be wrapped by a <Suspense> element
const Component = () => {
  const [value] = useAtom(loadableAtom)
  if (value.state === 'hasError') return <Text>{value.error}</Text>
  if (value.state === 'loading') {
    return <Text>Loading...</Text>
  }
  console.log(value.data) // Results of the Promise
  return <Text>Value: {value.data}</Text>
}
```

## atomWithObservable

Ref: https://github.com/pmndrs/jotai/pull/341

### Usage

```jsx
import { useAtom } from 'jotai'
import { atomWithObservable } from 'jotai/utils'
import { interval } from 'rxjs'
import { map } from 'rxjs/operators'

const counterSubject = interval(1000).pipe(map((i) => `#${i}`))
const counterAtom = atomWithObservable(() => counterSubject)

const Counter = () => {
  const [counter] = useAtom(counterAtom)
  return <div>count: {counter}</div>
}
```

The `atomWithObservable` function creates an atom from a rxjs (or similar) `subject` or `observable`.
Its value will be last value emitted from the stream.

To use this atom, you need to wrap your component with `<Suspense>`. Check out [guides/async](../guides/async.mdx).

### Initial value

`atomWithObservable` takes second optional parameter `{ initialValue }` that allows to specify initial value for the atom. If `initialValue` is provided then `atomWithObservable` will not suspend and will show initial value before receiving first value from observable. `initialValue` can be either a value or a function that returns a value

```js
const counterAtom = atomWithObservable(() => counterSubject, {
  initialValue: 10,
})

const counterAtom2 = atomWithObservable(() => counterSubject, {
  initialValue: () => Math.random(),
})
```

### Stackblitz

<Stackblitz id="vitejs-vite-3bkqrb" file="src%2FApp.tsx" />

## unwrap

The `unwrap` util will convert an async atom to a sync atom like `loadable`.
Unlike `loadable`, the fallback value can be configured.
Unlike `loadable`, the error won't be handled and just thrown.

The use case of `unwrap` is to ease deriving atoms.
This is especially useful for v2 API,
because `get` in the read function doesn't resolve promises.

### Signature

```ts
function unwrap<Value, Args extends unknown[], Result>(
  anAtom: WritableAtom<Value, Args, Result>,
): WritableAtom<Awaited<Value> | undefined, Args, Result>

function unwrap<Value, Args extends unknown[], Result, PendingValue>(
  anAtom: WritableAtom<Value, Args, Result>,
  fallback: (prev?: Awaited<Value>) => PendingValue,
): WritableAtom<Awaited<Value> | PendingValue, Args, Result>

function unwrap<Value>(anAtom: Atom<Value>): Atom<Awaited<Value> | undefined>

function unwrap<Value, PendingValue>(
  anAtom: Atom<Value>,
  fallback: (prev?: Awaited<Value>) => PendingValue,
): Atom<Awaited<Value> | PendingValue>
```

### Usage

```tsx
import { atom } from 'jotai'
import { unwrap } from 'jotai/utils'

const countAtom = atom(0)
const delayedCountAtom = atom(async (get) => {
  await new Promise((r) => setTimeout(r, 500))
  return get(countAtom)
})

const unwrapped1Atom = unwrap(delayedCountAtom)
// The value is `undefined` while pending

const unwrapped2Atom = unwrap(delayedCountAtom, (prev) => prev ?? 0)
// The value is `0` initially, and subsequent updates keep the previous value.
```

---

### Utilities Callback (`docs/utilities/callback.mdx`)

---
title: Callback
nav: 3.99
keywords: callback
published: false
---

## useAtomCallback

Ref: https://github.com/pmndrs/jotai/issues/60

### Usage

```ts
useAtomCallback<Result, Args extends unknown[]>(
  callback: (get: Getter, set: Setter, ...arg: Args) => Result,
  options?: Options
): (...args: Args) => Result
```

This hook is for interacting with atoms imperatively.
It takes a callback function that works like atom write function,
and returns a function that returns an atom value.

The callback to pass in the hook must be stable (should be wrapped with useCallback).

### Examples

```jsx
import { useEffect, useState, useCallback } from 'react'
import { Provider, atom, useAtom } from 'jotai'
import { useAtomCallback } from 'jotai/utils'

const countAtom = atom(0)

const Counter = () => {
  const [count, setCount] = useAtom(countAtom)
  return (
    <>
      {count} <button onClick={() => setCount((c) => c + 1)}>+1</button>
    </>
  )
}

const Monitor = () => {
  const [count, setCount] = useState(0)
  const readCount = useAtomCallback(
    useCallback((get) => {
      const currCount = get(countAtom)
      setCount(currCount)
      return currCount
    }, []),
  )
  useEffect(() => {
    const timer = setInterval(async () => {
      console.log(readCount())
    }, 1000)
    return () => {
      clearInterval(timer)
    }
  }, [readCount])
  return <div>current count: {count}</div>
}
```

### Stackblitz

<Stackblitz id="vitejs-vite-ekxjhs" file="src%2FApp.tsx" />

---

### Utilities Family (`docs/utilities/family.mdx`)

---
title: Family
nav: 3.5
keywords: family
---

## atomFamily

:::caution Deprecated
`atomFamily` is deprecated and will be removed in Jotai v3.

Please migrate to the [`jotai-family`](https://github.com/jotaijs/jotai-family) package, which provides the same API with additional features like `atomTree`.

**Migration:**

```bash
npm install jotai-family
```

```ts
// Before
import { atomFamily } from 'jotai/utils'

// After
import { atomFamily } from 'jotai-family'
```

The API is identical, so no code changes are needed beyond the import statement.
:::

Ref: https://github.com/pmndrs/jotai/issues/23

### Usage

```js
atomFamily(initializeAtom, areEqual): (param) => Atom
```

This will create a function that takes `param` and returns an atom.
If the atom has already been created, it will be returned from the cache.
`initializeAtom` is a function that can return any kind of atom (`atom()`, `atomWithDefault()`, ...).
Note that the `areEqual` argument is optional and compares
if two params are equal (defaults to `Object.is`).

To reproduce behavior similar to [Recoil's atomFamily/selectorFamily](https://recoiljs.org/docs/api-reference/utils/atomFamily),
specify a deepEqual function to `areEqual`. For example:

```js
import { atom } from 'jotai'
import { atomFamily } from 'jotai/utils'
import deepEqual from 'fast-deep-equal'

const fooFamily = atomFamily((param) => atom(param), deepEqual)
```

### TypeScript

The atom family types will be inferred from initializeAtom. Here's a typical usage with a primitive atom.

```ts
import type { PrimitiveAtom } from 'jotai'

/**
 * here the atom(id) returns a PrimitiveAtom<number>
 * and PrimitiveAtom<number> is a WritableAtom<number, SetStateAction<number>>
 */
const myFamily = atomFamily((id: number) => atom(id))
```

You can explicitly declare the type of parameter and atom type using TypeScript generics.

```ts
atomFamily<Param, AtomType extends Atom<unknown>>(
  initializeAtom: (param: Param) => AtomType,
  areEqual?: (a: Param, b: Param) => boolean
): AtomFamily<Param, AtomType>
```

Example with explicit types:

```ts
import { atom } from 'jotai'
import type { PrimitiveAtom } from 'jotai'
import { atomFamily } from 'jotai/utils'

const myFamily = atomFamily<number, PrimitiveAtom<number>>((id: number) =>
  atom(id),
)
```

### API Methods

The `atomFamily` function returns an object with the following methods:

#### `myFamily(param)`

Returns an atom for the given param. If the atom has already been created, it will be returned from the cache.

#### `myFamily.getParams()`

Returns an iterable of all params currently in the cache.

```js
const todoFamily = atomFamily((name) => atom(name))

todoFamily('foo')
todoFamily('bar')

for (const param of todoFamily.getParams()) {
  console.log(param) // 'foo', 'bar'
}
```

#### `myFamily.remove(param)`

Removes a specific param from the cache.

```js
todoFamily.remove('foo')
```

#### `myFamily.setShouldRemove(shouldRemove)`

Registers a `shouldRemove` function which runs immediately **and** when you are about to get an atom from the cache.

- `shouldRemove` is a function that takes two arguments: `createdAt` (in milliseconds) and `param`, and returns a boolean value.
- Setting `null` will remove the previously registered function.

```js
// Remove atoms older than 1 hour
todoFamily.setShouldRemove((createdAt, param) => {
  return Date.now() - createdAt > 60 * 60 * 1000
})
```

#### `myFamily.unstable_listen(callback)`

**⚠️ Unstable API**: This API is for advanced use cases and can change without notice.

Fires when an atom is created or removed. Returns a cleanup function.

```js
const cleanup = todoFamily.unstable_listen((event) => {
  console.log(event.type) // 'CREATE' or 'REMOVE'
  console.log(event.param) // the param
  console.log(event.atom) // the atom
})

// Later, stop listening
cleanup()
```

### Caveat: Memory Leaks

Internally, atomFamily is just a Map whose key is a param and whose value is an atom config.
Unless you explicitly remove unused params, this leads to memory leaks.
This is crucial if you use infinite number of params.

Use `myFamily.remove(param)` or `myFamily.setShouldRemove(shouldRemove)` to manage memory.

### Examples

```js
import { atom } from 'jotai'
import { atomFamily } from 'jotai/utils'

const todoFamily = atomFamily((name) => atom(name))

todoFamily('foo')
// this will create a new atom('foo'), or return the one if already created
```

```js
import { atom } from 'jotai'
import { atomFamily } from 'jotai/utils'

const todoFamily = atomFamily((name) =>
  atom(
    (get) => get(todosAtom)[name],
    (get, set, arg) => {
      const prev = get(todosAtom)
      set(todosAtom, { ...prev, [name]: { ...prev[name], ...arg } })
    },
  ),
)
```

```js
import { atom } from 'jotai'
import { atomFamily } from 'jotai/utils'

const todoFamily = atomFamily(
  ({ id, name }) => atom({ name }),
  (a, b) => a.id === b.id,
)
```

### Stackblitz

<Stackblitz id="vitejs-vite-rx6npn" file="src%2FApp.tsx" />

---

## Migration to jotai-family

For new projects or when updating existing code, we recommend using the [`jotai-family`](https://github.com/jotaijs/jotai-family) package instead. It provides:

- **Same API**: Drop-in replacement for `atomFamily`
- **Additional features**: Includes `atomTree` for hierarchical atom management
- **Better maintenance**: Dedicated package with focused development
- **Future-proof**: Will continue to be supported in Jotai v3 and beyond

See the [jotai-family documentation](https://github.com/jotaijs/jotai-family#readme) for more details.

---

### Utilities Lazy (`docs/utilities/lazy.mdx`)

---
title: Lazy
nav: 3.03
keywords: lazy,initialize,init,loading
---

When defining primitive atoms, their initial value has to be bound at definition time.
If creating that initial value is computationally expensive, or the value is not accessible during definition,
it would be best to postpone the atom's initialization until its [first use in the store](#using-multiple-stores).

```jsx
const imageDataAtom = atom(initializeExpensiveImage()) // 1) has to be computed here

function Home() {
  ...
}

function ImageEditor() {
  // 2) used only in this route
  const [imageData, setImageData] = useAtom(imageDataAtom);
  ...
}

function App() {
  return (
    <Router>
      <Route path="/" component={Home} />
      <Route path="/edit" component={ImageEditor} />
    </Router>
  )
}
```

## atomWithLazy

Ref: https://github.com/pmndrs/jotai/pull/2465

We can use `atomWithLazy` to create a primitive atom whose initial value will be computed at [first use in the store](#using-multiple-stores).
After initialization, it will behave like a regular primitive atom (can be written to).

### Usage

```jsx
import { atomWithLazy } from 'jotai/utils'

// passing the initialization function
const imageDataAtom = atomWithLazy(initializeExpensiveImage)

function Home() {
  ...
}

function ImageEditor() {
  // only gets initialized if user goes to `/edit`.
  const [imageData, setImageData] = useAtom(imageDataAtom);
  ...
}

function App() {
  return (
    <Router>
      <Route path="/" component={Home} />
      <Route path="/edit" component={ImageEditor} />
    </Router>
  )
}
```

### Using multiple stores

Since each store is its separate universe, the initial value will be recreated exactly once per store (unless using something like `jotai-scope`, which fractures a store into smaller universes).

```ts
type RGB = [number, number, number];

function randomRGB(): RGB {
  ...
}

const lift = (value: number) => ([r, g, b]: RGB) => {
  return [r + value, g + value, b + value]
}

const colorAtom = lazyAtom(randomRGB)

let store = createStore()

console.log(store.get(colorAtom)) // [0, 36, 128]
store.set(colorAtom, lift(8))
console.log(store.get(colorAtom)) // [8, 44, 136]

// recreating store, sometimes done when logging out or resetting the app in some way
store = createStore()

console.log(store.get(colorAtom)) // [255, 12, 46] -- a new random color
```

---

### Utilities Reducer (`docs/utilities/reducer.mdx`)

---
title: Reducer
nav: 3.99
keywords: reducer,action,dispatch
published: false
---

## atomWithReducer

Ref: https://github.com/pmndrs/jotai/issues/38

```js
import { atomWithReducer } from 'jotai/utils'

const countReducer = (prev, action) => {
  if (action.type === 'inc') return prev + 1
  if (action.type === 'dec') return prev - 1
  throw new Error('unknown action type')
}

const countReducerAtom = atomWithReducer(0, countReducer)
```

### Stackblitz

<Stackblitz id="vitejs-vite-bbpmjn" file="src%2FApp.tsx" />

## useReducerAtom

See [useReducerAtom](../recipes/use-reducer-atom.mdx) recipe.

---

### Utilities Resettable (`docs/utilities/resettable.mdx`)

---
title: Resettable
nav: 3.04
keywords: reset,default
---

## atomWithReset

Ref: https://github.com/pmndrs/jotai/issues/41

```ts
function atomWithReset<Value>(
  initialValue: Value,
): WritableAtom<Value, SetStateAction<Value> | typeof RESET>
```

Creates an atom that could be reset to its `initialValue` with
[`useResetAtom`](use-reset-atom.mdx) hook. It works exactly the same
way as primitive atom would, but you are also able to set it to a special value
[`RESET`](reset.mdx). See examples in [Resettable atoms](../utilities/resettable.mdx).

### Example

```js
import { atomWithReset } from 'jotai/utils'

const dollarsAtom = atomWithReset(0)
const todoListAtom = atomWithReset([
  { description: 'Add a todo', checked: false },
])
```

## RESET

Ref: https://github.com/pmndrs/jotai/issues/217

```ts
const RESET: unique symbol
```

Special value that is accepted by [Resettable atoms](../utilities/resettable.mdx)
created with [`atomWithReset`](../utilities/resettable.mdx), [`atomWithDefault`](../utilities/resettable.mdx)
or writable atom created with `atom` if it accepts `RESET` symbol.

### Example

```jsx
import { atom, useSetAtom } from 'jotai'
import { atomWithReset, useResetAtom, RESET } from 'jotai/utils'

const dollarsAtom = atomWithReset(0)
const centsAtom = atom(
  (get) => get(dollarsAtom) * 100,
  (get, set, newValue: number | typeof RESET) =>
    set(dollarsAtom, newValue === RESET ? newValue : newValue / 100)
)

const ResetExample = () => {
  const setDollars = useSetAtom(dollarsAtom)
  const resetCents = useResetAtom(centsAtom)

  return (
    <>
      <button onClick={() => setDollars(RESET)}>Reset dollars</button>
      <button onClick={resetCents}>Reset cents</button>
    </>
  )
}
```

## useResetAtom

```ts
function useResetAtom<Value>(
  anAtom: WritableAtom<Value, typeof RESET>,
): () => void | Promise<void>
```

Resets a [Resettable atom](../utilities/resettable.mdx) to its initial value.

### Example

```jsx
import { useResetAtom } from 'jotai/utils'
import { todoListAtom } from './store'

const TodoResetButton = () => {
  const resetTodoList = useResetAtom(todoListAtom)
  return <button onClick={resetTodoList}>Reset</button>
}
```

## atomWithDefault

Ref: https://github.com/pmndrs/jotai/issues/352

### Usage

This is a function to create a resettable primitive atom.
Its default value can be specified with a read function instead of a static initial value.

```js
import { atomWithDefault } from 'jotai/utils'

const count1Atom = atom(1)
const count2Atom = atomWithDefault((get) => get(count1Atom) * 2)
```

### Stackblitz

<Stackblitz id="vitejs-vite-gffb5v" file="src%2FApp.tsx" />

### Resetting default values

You can reset the value of an `atomWithDefault` atom to its original default value.

```jsx
import { useAtom } from 'jotai'
import { atomWithDefault, useResetAtom, RESET } from 'jotai/utils'

const count1Atom = atom(1)
const count2Atom = atomWithDefault((get) => get(count1Atom) * 2)

const Counter = () => {
  const [count1, setCount1] = useAtom(count1Atom)
  const [count2, setCount2] = useAtom(count2Atom)
  const resetCount2 = useResetAtom(count2Atom)

  return (
    <>
      <div>
        count1: {count1}, count2: {count2}
      </div>
      <button onClick={() => setCount1((c) => c + 1)}>increment count1</button>
      <button onClick={() => setCount2((c) => c + 1)}>increment count2</button>
      <button onClick={() => resetCount2()}>Reset with useResetAtom</button>
      <button onClick={() => setCount2(RESET)}>Reset with RESET const</button>
    </>
  )
}
```

This can be useful when an `atomWithDefault` atom value is overwritten
using the `set` function, in which case the provided `getter` function
is no longer used and any change in dependencies atoms will not trigger an update.

Resetting the value allows us to restore its original default value,
discarding changes made previously via the `set` function.

## atomWithRefresh

```ts
function atomWithRefresh<Value>(
  read: Read<Value, [], void>,
): WritableAtom<Value, [], void>
```

Creates an atom that we can refresh,
which is to force reevaluating the read function.

This is helpful when you need to refresh asynchronous data.
It can also be used to implement "pull to refresh" functionality.

```ts
function atomWithRefresh<Value, Args extends unknown[], Result>(
  read: Read<Value, Args, Result>,
  write: Write<Value, Args, Result>,
): WritableAtom<Value, Args | [], Result | void>
```

Passing zero arguments to `set` will refresh.
Passing one or more arguments to `set` will call "write" function.

### Example

Here's how you'd use it to implement an refresh-able source of data:

```js
import { atomWithRefresh } from 'jotai/utils'

const postsAtom = atomWithRefresh((get) =>
  fetch('https://jsonplaceholder.typicode.com/posts').then((r) => r.json()),
)
```

In a component:

```jsx
const PostsList = () => {
  const [posts, refreshPosts] = useAtom(postsAtom)

  return (
    <div>
      <ul>
        {posts.map((post) => (
          <li key={post.id}>{post.title}</li>
        ))}
      </ul>

      {/* Clicking this button will re-fetch the posts */}
      <button type="button" onClick={() => refreshPosts()}>
        Refresh posts
      </button>
    </div>
  )
}
```

---

### Utilities Select (`docs/utilities/select.mdx`)

---
title: Select
nav: 3.99
keywords: select
published: false
---

## selectAtom

⚠️ Unlike its name, `selectAtom` is provided as an escape hatch. Using it means building not 100% pure atom model. Prefer using derived atoms and use `selectAtom` only when `equalityFn` or `prevSlice` is unavoidable.

### Signatures

```ts
function selectAtom<Value, Slice>(
  anAtom: Atom<Value>,
  selector: (v: Value, prevSlice?: Slice) => Slice,
  equalityFn: (a: Slice, b: Slice) => boolean = Object.is,
): Atom<Slice>
```

This function creates a derived atom whose value is a function of the original atom's value,
determined by `selector.`
The selector function runs whenever the original atom changes; it updates the derived atom
only if `equalityFn` reports that the derived value has changed.
By default, `equalityFn` is reference equality, but you can supply your favorite deep-equals
function to stabilize the derived value where necessary.

### Examples

```js
const defaultPerson = {
  name: {
    first: 'Jane',
    last: 'Doe',
  },
  birth: {
    year: 2000,
    month: 'Jan',
    day: 1,
    time: {
      hour: 1,
      minute: 1,
    },
  },
}

// Original atom.
const personAtom = atom(defaultPerson)

// Tracks person.name. Updated when person.name object changes, even
// if neither name.first nor name.last actually change.
const nameAtom = selectAtom(personAtom, (person) => person.name)

// Tracks person.birth. Updated when year, month, day, hour, or minute changes.
// Use of deepEquals means that this atom doesn't update if birth field is
// replaced with a new object containing the same data. E.g., if person is re-read
// from a database.
const birthAtom = selectAtom(personAtom, (person) => person.birth, deepEquals)
```

### Hold stable references

As always, to prevent an infinite loop when using `useAtom` in render cycle, you must provide `useAtom` a stable reference of your atoms.
For `selectAtom`, we need **both** the base atom and the selector to be stable.

```js
const [value] = useAtom(selectAtom(atom(0), (val) => val)) // So this will cause an infinite loop
```

You have multiple options in order to satisfy these constraints:

```js
const baseAtom = atom(0) // Stable
const baseSelector = (v) => v // Stable
const Component = () => {
  // Solution 1: Memoize the whole resulting atom with "useMemo"
  const [value] = useAtom(useMemo(() => selectAtom(baseAtom, (v) => v), []))

  // Solution 2: Memoize the inline callback with "useCallback"
  const [value] = useAtom(
    selectAtom(
      baseAtom,
      useCallback((v) => v, []),
    ),
  )

  // Solution 3: All constraints are already satisfied
  const [value] = useAtom(selectAtom(baseAtom, baseSelector))
}
```

### Stackblitz

<Stackblitz id="vitejs-vite-tgejq7" file="src%2FApp.tsx" />

---

### Utilities Split (`docs/utilities/split.mdx`)

---
title: Split
nav: 3.99
keywords: select
published: false
---

## splitAtom

The `splitAtom` utility is designed for scenarios where you need to obtain an atom for each element in a list. It operates on read/write atoms containing a list, returning an atom that holds a list of atoms, each corresponding to an item in the original list.

### Signature

A simplified type signature for `splitAtom` would be:

```ts
type SplitAtom = <Item, Key>(
  arrayAtom: PrimitiveAtom<Array<Item>>,
  keyExtractor?: (item: Item) => Key
): Atom<Array<PrimitiveAtom<Item>>>
```

### Key Features

1. The returned atom contains a dispatch function in the `write` direction (since v1.6.4), providing a simple way to modify the original atom with actions like `remove`, `insert`, and `move`.

2. An optional `keyExtractor` function can be provided as a second argument to enhance stability and performance.

### Key Extractor

The `splitAtom` utility supports a second argument which is a key extractor function:

```ts
export function splitAtom<Item, Key>(
  arrAtom: WritableAtom<Item[], [Item[]], void> | Atom<Item[]>,
  keyExtractor?: (item: Item) => Key,
)
```

Important considerations for the `keyExtractor`:

- If `splitAtom` is used within a React render loop, the `keyExtractor` must be a stable function that maintains object equality (shallow equality). This requirement doesn't apply outside of render loops.
- Providing a `keyExtractor` enhances the stability of the atom output (which makes memoization hit cache more often). It prevents unnecessary subatom recreation due to index shifts in the source array.
- `keyExtractor` is an optional optimization that should only be used if the extracted key is guaranteed unique for each item in the array.

### Example Usage

Here's an example demonstrating the use of `splitAtom`:

<Stackblitz id="vitejs-vite-oavdw2" file="src%2FApp.tsx" />

```tsx
import { Provider, atom, useAtom, PrimitiveAtom } from 'jotai'
import { splitAtom } from 'jotai/utils'
import './styles.css'

const initialState = [
  {
    task: 'help the town',
    done: false,
  },
  {
    task: 'feed the dragon',
    done: false,
  },
]

const todosAtom = atom(initialState)
const todoAtomsAtom = splitAtom(todosAtom)

type TodoType = (typeof initialState)[number]

const TodoItem = ({
  todoAtom,
  remove,
}: {
  todoAtom: PrimitiveAtom<TodoType>
  remove: () => void
}) => {
  const [todo, setTodo] = useAtom(todoAtom)
  return (
    <div>
      <input
        value={todo.task}
        onChange={(e) => {
          setTodo((oldValue) => ({ ...oldValue, task: e.target.value }))
        }}
      />
      <input
        type="checkbox"
        checked={todo.done}
        onChange={() => {
          setTodo((oldValue) => ({ ...oldValue, done: !oldValue.done }))
        }}
      />
      <button onClick={remove}>remove</button>
    </div>
  )
}

const TodoList = () => {
  const [todoAtoms, dispatch] = useAtom(todoAtomsAtom)
  return (
    <ul>
      {todoAtoms.map((todoAtom) => (
        <TodoItem
          todoAtom={todoAtom}
          remove={() => dispatch({ type: 'remove', atom: todoAtom })}
        />
      ))}
    </ul>
  )
}

const App = () => (
  <Provider>
    <TodoList />
  </Provider>
)

export default App
```

This example demonstrates how to use `splitAtom` to manage a list of todo items, allowing individual manipulation of each item while maintaining the overall list atom.

---

### Utilities Ssr (`docs/utilities/ssr.mdx`)

---
title: SSR
nav: 3.02
keywords: ssr,server,hydrate,hydration,next,nextjs,gatsby,remix,waku,framework
---

## useHydrateAtoms

Ref: https://github.com/pmndrs/jotai/issues/340

### Usage

```js
import { atom, useAtom } from 'jotai'
import { useHydrateAtoms } from 'jotai/utils'

const countAtom = atom(0)
const CounterPage = ({ countFromServer }) => {
  useHydrateAtoms([[countAtom, countFromServer]])
  const [count] = useAtom(countAtom)
  // count would be the value of `countFromServer`, not 0.
}
```

The primary use case for `useHydrateAtoms` are SSR apps like Next.js, where an initial value is e.g. fetched on the server, which can be passed to a component by props.

⚠️ Note: Although the term "hydrate" might suggest server-side usage, this hook is designed for client-side code and should be used with the [`'use client'` directive](https://react.dev/reference/rsc/use-client).

```ts
// Definition
function useHydrateAtoms(
  values: Iterable<readonly [Atom<unknown>, unknown]>,
  options?: { store?: Store },
): void
```

The hook takes an iterable of tuples containing `[atom, value]` as an argument and optional options.

```js
// Usage with an array, specifying a store
useHydrateAtoms(
  [
    [countAtom, 42],
    [frameworkAtom, 'Next.js'],
  ],
  { store: myStore },
)
// Or with a map
useHydrateAtoms(new Map([[count, 42]]))
```

Atoms can only be hydrated once per store. Therefore, if the initial value used is changed during rerenders, it won't update the atom value.
If there is a unique need to re-hydrate a previously hydrated atom, pass the optional dangerouslyForceHydrate as true
and note that it may behave wrongly in concurrent rendering.

```js
useHydrateAtoms(
  [
    [countAtom, 42],
    [frameworkAtom, 'Next.js'],
  ],
  {
    dangerouslyForceHydrate: true,
  },
)
```

If there's a need to hydrate in multiple stores, use multiple `useHydrateAtoms` hooks to achieve that.

```js
useHydrateAtoms([
  [countAtom, 42],
  [frameworkAtom, 'Next.js'],
])
useHydrateAtoms(
  [
    [countAtom, 17],
    [frameworkAtom, 'Gatsby'],
  ],
  { store: myStore },
)
```

If you are using TypeScript with target `ES5`, you might need `as const` cast on the array to preserve the tuple type.

```ts
useHydrateAtoms([
  [countAtom, 42],
  [frameworkAtom, 'Next.js'],
] as const)
```

Or you may need to use a Map when passing the atom value to useHydrateAtoms. You can find a working example in the [Initializing State on Render docs](https://jotai.org/docs/guides/initialize-atom-on-render#using-typescript).

### Demo

<Stackblitz id="stackblitz-starters-b7cvxi" file="pages%2Findex.tsx" />

There's more examples in the [Next.js section](../guides/nextjs.mdx).

---

### Utilities Storage (`docs/utilities/storage.mdx`)

---
title: Storage
nav: 3.01
keywords: storage,localstorage,sessionstorage,asyncstorage,persist,persistence
---

## atomWithStorage

Ref: https://github.com/pmndrs/jotai/pull/394

```jsx
import { useAtom } from 'jotai'
import { atomWithStorage } from 'jotai/utils'

const darkModeAtom = atomWithStorage('darkMode', false)

const Page = () => {
  const [darkMode, setDarkMode] = useAtom(darkModeAtom)

  return (
    <>
      <h1>Welcome to {darkMode ? 'dark' : 'light'} mode!</h1>
      <button onClick={() => setDarkMode(!darkMode)}>toggle theme</button>
    </>
  )
}
```

The `atomWithStorage` function creates an atom with a value persisted in `localStorage` or `sessionStorage` for React or `AsyncStorage` for React Native.

### Parameters

**key** (required): a unique string used as the key when syncing state with localStorage, sessionStorage, or AsyncStorage

**initialValue** (required): the initial value of the atom

**storage** (optional): an object with the following methods:

- **getItem(key, initialValue)** (required): Reads an item from storage, or falls back to the `initialValue`
- **setItem(key, value)** (required): Saves an item to storage
- **removeItem(key)** (required): Deletes the item from storage
- **subscribe(key, callback, initialValue)** (optional): A method which subscribes to external storage updates.

**options** (optional): an object with the following properties:

- **getOnInit** (optional, by default **false**): A boolean value indicating whether to get item from storage on initialization. Note that in an SPA with `getOnInit` either not set or `false` you will always get the initial value instead of the stored value on initialization. If the stored value is preferred set `getOnInit` to `true`.

If not specified, the default storage implementation uses `localStorage` for storage/retrieval, `JSON.stringify()`/`JSON.parse()` for serialization/deserialization, and subscribes to `storage` events for cross-tab synchronization.

<Stackblitz id="vitejs-vite-xvlgfxrk" file="src%2FApp.tsx" />

### `createJSONStorage` util

To create a custom storage implementation with `JSON.stringify()`/`JSON.parse()` for the `storage` option, `createJSONStorage` util is provided.

Usage:

```js
const storage = createJSONStorage(
  // getStringStorage
  () => window.localStorage, // or window.sessionStorage, asyncStorage or alike
  // options (optional)
  {
    reviver, // optional reviver option for JSON.parse
    replacer, // optional replacer option for JSON.stringify
  },
)
```

Note: `JSON.parse` is not type safe. If it can't accept any types, some kind of validation would be necessary for production apps.

### Server-side rendering

When using `atomWithStorage` in an environment that renders on the server, such as Next.js or Waku, the storage backing the atom should safely return `undefined` on the server.

For example, use a guarded `createJSONStorage` getter when using `sessionStorage` in a Next.js static export:

```js
import { atomWithStorage, createJSONStorage } from 'jotai/utils'

const storage = createJSONStorage(() =>
  typeof window !== 'undefined' ? window.sessionStorage : undefined,
)

const someAtom = atomWithStorage('some-key', someInitialValue, storage)
```

Any JSX markup that depends on the value of a stored atom (e.g., a `className` or `style` prop) will use the `initialValue` when rendered on the server (since `localStorage` and `sessionStorage` are not available on the server).

This means that there will be a mismatch between what is originally served to the user's browser as HTML and what is expected by React during the rehydration process if the user has a `storedValue` that differs from the `initialValue`.

The suggested workaround for this issue is to only render the content dependent on the `storedValue` client-side by wrapping it in a [custom `<ClientOnly>` wrapper](https://www.joshwcomeau.com/react/the-perils-of-rehydration/#abstractions), which only renders after rehydration. Alternative solutions are technically possible, but would require a brief "flicker" as the `initialValue` is swapped to the `storedValue`, which can result in an unpleasant user experience, so this solution is advised.

### Deleting an item from storage

For the case you want to delete an item from storage,
the atom created with `atomWithStorage` accepts the `RESET` symbol on write.

See the following example for the usage:

```jsx
import { useAtom } from 'jotai'
import { atomWithStorage, RESET } from 'jotai/utils'

const textAtom = atomWithStorage('text', 'hello')

const TextBox = () => {
  const [text, setText] = useAtom(textAtom)

  return (
    <>
      <input value={text} onChange={(e) => setText(e.target.value)} />
      <button onClick={() => setText(RESET)}>Reset (to 'hello')</button>
    </>
  )
}
```

If needed, you can also do conditional resets based on previous value.

This can be particularly useful if you wish to clear keys in localStorage if previous values meet a condition.

Below exemplifies this usage that clears the `visible` key whenever the previous value is `true`.

```jsx
import { useAtom } from 'jotai'
import { atomWithStorage, RESET } from 'jotai/utils'

const isVisibleAtom = atomWithStorage('visible', false)

const TextBox = () => {
  const [isVisible, setIsVisible] = useAtom(isVisibleAtom)

  return (
    <>
      {isVisible && <h1>Header is visible!</h1>}
      <button onClick={() => setIsVisible((prev) => (prev ? RESET : true))}>
        Toggle visible
      </button>
    </>
  )
}
```

### React-Native implementation

You can use any library that implements `getItem`, `setItem` & `removeItem`.
Let's say you would use the standard AsyncStorage provided by the community.

```js
import { atomWithStorage, createJSONStorage } from 'jotai/utils'
import AsyncStorage from '@react-native-async-storage/async-storage'

const storage = createJSONStorage(() => AsyncStorage)
const content = {} // anything JSON serializable
const storedAtom = atomWithStorage('stored-key', content, storage)
```

**Note** set `getOnInit` to `true` if you want the atom to return the stored value immediately on initialization instead of the default value.

**getOnInit true vs. false example**

<details>

```jsx
// Assume localStorage already contains: { "symbol": "BTC_USDC" }

// Without getOnInit (default behavior)
const symbolAtom = atomWithStorage('symbol', 'SOL_USDC')

function App() {
  const symbol = useAtomValue(symbolAtom)

  useEffect(() => {
    console.log('symbol', symbol)
  }, [symbol])

  return <div>{symbol}</div>
}

// Console output WITHOUT getOnInit:
// LOG "symbol" SOL_USDC  (initial render)
// LOG "symbol" BTC_USDC  (after storage loads)

// With getOnInit set to true
const symbolAtom = atomWithStorage('symbol', 'SOL_USDC', undefined, {
  getOnInit: true,
})

function App() {
  const symbol = useAtomValue(symbolAtom)

  useEffect(() => {
    console.log('symbol', symbol)
  }, [symbol])

  return <div>{symbol}</div>
}

// Console output WITH getOnInit:
// LOG "symbol" BTC_USDC  (gets stored value immediately)
```

</details>

#### Notes with AsyncStorage (since v2.2.0)

With AsyncStorage (as with any asynchronous storage), the atom value becomes async.
When updating the atom by referencing the current value, then you'll need to `await` it.

```js
const countAtom = atomWithStorage('count-key', 0, anyAsyncStorage)
const Component = () => {
  const [count, setCount] = useAtom(countAtom)
  const increment = () => {
    setCount(async (promiseOrValue) => (await promiseOrValue) + 1)
  }
  // ...
}
```

### Validating stored values

To add runtime validation to your storage atoms, you will need to create a custom implementation of storage.

Below is an example that utilizes Zod to validate values stored in `localStorage` with cross-tab synchronization.

```js
import { atomWithStorage } from 'jotai/utils'
import { z } from 'zod'

const myNumberSchema = z.number().int().nonnegative()

const storedNumberAtom = atomWithStorage('my-number', 0, {
  getItem(key, initialValue) {
    const storedValue = localStorage.getItem(key)
    try {
      return myNumberSchema.parse(JSON.parse(storedValue ?? ''))
    } catch {
      return initialValue
    }
  },
  setItem(key, value) {
    localStorage.setItem(key, JSON.stringify(value))
  },
  removeItem(key) {
    localStorage.removeItem(key)
  },
  subscribe(key, callback, initialValue) {
    if (
      typeof window === 'undefined' ||
      typeof window.addEventListener === 'undefined'
    ) {
      return
    }
    const handler = (e) => {
      if (e.storageArea === localStorage && e.key === key) {
        let newValue
        try {
          newValue = myNumberSchema.parse(JSON.parse(e.newValue ?? ''))
        } catch {
          newValue = initialValue
        }
        callback(newValue)
      }
    }
    window.addEventListener('storage', handler)
    return () => window.removeEventListener('storage', handler)
  },
})
```

We also have a new util `unstable_withStorageValidator` to simplify some cases.
The above case would become:

```js
import {
  atomWithStorage,
  createJSONStorage,
  unstable_withStorageValidator as withStorageValidator,
} from 'jotai/utils'
import { z } from 'zod'

const myNumberSchema = z.number().int().nonnegative()
const isMyNumber = (v) => myNumberSchema.safeParse(v).success

const storedNumberAtom = atomWithStorage(
  'my-number',
  0,
  withStorageValidator(isMyNumber)(createJSONStorage()),
)
```

---

--- METRICS ---
- Files Extracted: 81
- Estimated Token Budget: ~67092 tokens
- Canonical Reference: https://codewiki.google/github.com/pmndrs/jotai
