---
title: Async
nav: 3.03
keywords: 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,
}
```

```jsx
import { loadable } from "jotai/utils"

const asyncAtom = atom(async (get) => ...)
const loadableAtom = loadable(asyncAtom)
// Does not need to be wrapped by a <Suspense> element
const 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 Promise
  return <Text>Value: {value.data}</Text>
}
```

## atomWithObservable

Ref: https://github.com/pmndrs/jotai/pull/341

### Usage

```jsx
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](../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

```js
const counterAtom = atomWithObservable(() => counterSubject, {
  initialValue: 10,
})

const counterAtom2 = atomWithObservable(() => counterSubject, {
  initialValue: () => Math.random(),
})
```

### Stackblitz

<Stackblitz id="vitejs-vite-3bkqrb" file="src%2FApp.tsx" />

## 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

```ts
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

```tsx
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 pending

const unwrapped2Atom = unwrap(delayedCountAtom, (prev) => prev ?? 0)
// The value is `0` initially, and subsequent updates keep the previous value.
```
