Skip to main content


👻 Primitive and flexible state management for React
Go to Latest
---title: Asyncnav: 3.03keywords: 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
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,}```
```jsximport { loadable } from "jotai/utils"
const asyncAtom = atom(async (get) => ...)const loadableAtom = loadable(asyncAtom)// Does not need to be wrapped by a <Suspense> elementconst Component = () => { const [value] = useAtom(loadableAtom) if (value.state === 'hasError') return <Text>{value.error}</Text> if (value.state === 'loading') { return <Text>Loading...</Text> } console.log( // Results of the Promise return <Text>Value: {}</Text>}```
## atomWithObservable
### Usage
```jsximport { 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
```jsconst counterAtom = atomWithObservable(() => counterSubject, { initialValue: 10,})
const counterAtom2 = atomWithObservable(() => counterSubject, { initialValue: () => Math.random(),})```
### Codesandbox
<CodeSandbox id="88pnt" />## 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
```tsfunction 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
```tsximport { 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.```