--- title: Async description: This doc describes about the behavior with async. nav: 1.03 --- 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 ( ) } ``` Alternatively, you could avoid the inherent suspending that Jotai does for you, by wrapping your atoms with the [`loadable` API](../utils/loadable.mdx). 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://...').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`. It cannot accept `Promise` as a value so preceding code would not typecheck. To accomodate for that you need to type your atom explicitly and add `Promise` as accepted value. ```ts const baseAtom = atom>(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](../utils/loadable.mdx) to avoid suspending To use async atoms, you need to wrap your component tree with ``. > If you have a ``, place **at least one** `` inside said ``; otherwise, it may cause an endless loop while rendering the components. ```jsx const App = () => ( ) ``` Having more ``s in the component tree is also possible and must be considered to profit from Jotai inherent handling at best.