Async
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
.
{state: 'loading' | 'hasData' | 'hasError',data?: any,error?: any,}
import { 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(value.data) // Results of the Promisereturn <Text>Value: {value.data}</Text>}
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(),})