Async
Async support is first class in jotai. It fully leverages React Suppense.
Technically, Suspense usage other than React.lazy is still unsupported / undocumented in React 17. If this is blocking, check out guides/no-suspense.
Suspense
To use async atoms, you need to wrap your component tree with <Suspense>.
If you have <Provider> at least one <Suspense> is placed inside the <Provider>.
const App = () => (
  <Provider>
    <Suspense fallback="Loading...">
      <Layout />
    </Suspense>
  </Provider>
)
Having more <Suspense>s in the component tree is possible.
Async read atom
The read function of an atom can return a promise.
It will suspend and re-render when the promise is fulfilled.
Most importantly, useAtom only returns a resolved value.
const countAtom = atom(1)
const asyncCountAtom = atom(async (get) => get(countAtom) * 2)
// even though the read function returns a promise,
const Component = () => {
  const [num] = useAtom(asyncCountAtom)
  // `num` is guaranteed to be a number.
}
An atom becomes async not only if the atom read function is async, but also one or more of its dependencies are async.
const anotherAtom = atom((get) => get(asyncCountAtom) / 2)
// even though this atom doesn't return a promise,
// it is a read async atom because `asyncCountAtom` is async.
Async write atom
There are another kind of async atoms, called async write atom.
When write function of atom returns a promise, it may suspend.
This happens only if the atom is used directly with useAtom,
regardless of its value. (The atom value can be just null.)
const countAtom = atom(1)
const asyncIncrementAtom = atom(null, async (get, set) => {
  // await something
  set(countAtom, get(countAtom) + 1)
})
const Component = () => {
  const [, increment] = useAtom(asyncIncrementAtom)
  // it will suspend while `increment` is pending.
}
There's no way to know as of now if an atom suspends because of
readorwrite.