Skip to main content
Module

x/jotai/docs/basics/async.mdx

👻 Primitive and flexible state management for React
Go to Latest
File
---title: Asyncdescription: This doc describes about the behavior with async.nav: 1.03---
Async support is first class in jotai. It fully leverages React Suspense.
> Technically, Suspense usage other than React.lazy is still unsupported / undocumented in React 17. If this is blocking, check out [guides/no-suspense](../guides/no-suspense.mdx).## Suspense
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.```jsxconst App = () => ( <Provider> <Suspense fallback="Loading..."> <Layout /> </Suspense> </Provider>)```
Having more `<Suspense>`s in the component tree is also possible.
## Async read atom
The `read` function of an atom can return a promise.It will suspend and re-render once the promise fulfills.
Most importantly, useAtom only returns a resolved value.
```jsconst countAtom = atom(1)const asyncCountAtom = atom(async (get) => get(countAtom) * 2)// even though the read function returns a promise,
const Component = () => { const [num] = useAtom(asyncCountAtom) // `num` is guaranteed to be a number.}```
An atom becomes async not only if the atom read function is async,but also if one or more of its dependencies are async.
```jsconst anotherAtom = atom((get) => get(asyncCountAtom) / 2)// even though this atom doesn't return a promise,// it's a read async atom because `asyncCountAtom` is async.```
<details><summary>Async write atom behavior until v1.3.9</summary>(This is no longer the case since v1.4.0.)
## Async write atom
Async write atoms are another kind of async atom.When the `write` function of atom returns a promise, it may suspend.This happens if the atom is used directly with useAtom,regardless of its value. (The atom value can be `null`.)
```jsconst countAtom = atom(1)const asyncIncrementAtom = atom(null, async (get, set) => { // await something set(countAtom, get(countAtom) + 1)})
const Component = () => { const [, increment] = useAtom(asyncIncrementAtom) // it will suspend while `increment` is pending.}```
> There's no way to know as of now if an atom suspends because of `read` or `write`.### Triggering `Suspense` fallback of write atom
This section applies only for "async write atom" not "async read atom", which works differently with `Suspense`.
**A write atom will trigger the `Suspense` fallback if:**
* the atom's write argument (2nd one) is async * the awaited call is made directly, and not from inside another containing functionThis _will_ trigger the `Suspense` fallback:
```tsconst writeAtom = atom(null, async (get, set) => { const response = await new Promise<string>((resolve, _reject) => { setTimeout(() => { resolve('some returned value') }, 2000) }) set(somePrimitiveAtom, 'The returned value is: ' + response)})```
This _will not_ trigger the `Suspense` fallback:
```tsconst writeAtom = atom(null, (get, set) => { const getResponse = async () => { const response = await new Promise<string>((resolve, _reject) => { setTimeout(() => { resolve('some returned value') }, 2000) }) set(somePrimitiveAtom, 'The returned value is: ' + response) } getResponse()})```
But **_both_** of the above will still set `somePrimitiveAtom` to the correct values.
</details>