Async
All atoms support async behavior such as async read or async write. However there are APIs for more control described here.
unwrap
The unwrap util converts an async atom to a synchronous atom, making it
easier to derive other atoms from its resolved value. While the promise is
pending, it returns undefined or a configurable fallback, which can use
the previous resolved value. Errors are not caught and are thrown when
the atom is read.
This is useful because get in an atom's read function returns promises
as-is rather than resolving them.
Signature
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
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 pendingconst unwrapped2Atom = unwrap(delayedCountAtom, (prev) => prev ?? 0)// The value is `0` initially, and subsequent updates keep the previous value.
atomWithObservable
Ref: https://github.com/pmndrs/jotai/pull/341
Usage
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.
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
const counterAtom = atomWithObservable(() => counterSubject, {initialValue: 10,})const counterAtom2 = atomWithObservable(() => counterSubject, {initialValue: () => Math.random(),})
Stackblitz
Related APIs
atomWithRefresh: re-evaluates an atom's read function to refresh data or retry a request.useAtomValueRaw: reads an atom's value without resolving promises or suspending.useAtomValueRawSync: the same asuseAtomValueRaw, but usesuseSyncExternalStoreto avoid tearing and catch updates during mount.
loadable
The loadable util has been removed from jotai/utils in Jotai v3.
Use unwrap to derive a synchronous atom from an async atom
with a configurable fallback while loading. Errors are still thrown.
For reading an async atom's value in a component without suspending, see
useAtomValueRaw and
useAtomValueRawSync.
If you need to preserve the previous loading, hasData, and hasError
states, see the v3 migration guide
for a userland replacement built on unwrap.