JotaiJotai

状態
Primitive and flexible state management for React

No Suspense

The content of this page will be easier to follow if you have taken a look at the basics/async part of the docs.

Sometimes we need to wrap our components in suspense to use asynchronous atoms.

But sometimes we're not allowed to wrap our components in Suspense, So we're going to do some hacks below and and make our async atoms synchronous.

Async read (Derived async atoms)

Check this derived async atom:

const urlAtom = atom('https://json.host.com')
const fetchUrlAtom = atom(async (get) => {
const response = await fetch(get(urlAtom))
return await response.json()
})

It needs Suspense because the read function returns a promise(async function).

We shouldn't return a promise if we don't need it to suspend, so we have to change the structure slightly.

Here's the new code.

const fetchResultAtom = atom({ loading: true, error: null, data: null })
const runFetchAtom = atom(
(get) => get(fetchResultAtom),
(_get, set, url) => {
const fetchData = async () => {
set(fetchResultAtom, (prev) => ({ ...prev, loading: true }))
try {
const response = await fetch(url)
const data = await response.json()
set(fetchResultAtom, { loading: false, error: null, data })
} catch (error) {
set(fetchResultAtom, { loading: false, error, data: null })
}
}
fetchData()
}
)
runFetchAtom.onMount = (runFetch) => {
runFetch('https://json.host.com')
}
const Component = () => {
const [result] = useAtom(runFetchAtom)
console.log(result) // { loading: ..., error: ..., data: ... }
return <div>...</div>
}
For async write until v1.3.9

(This is no longer the case since v1.4.0.)

Async write (Asynchronous actions)

The original code is:

const fetchCountAtom = atom(
(get) => get(countAtom),
async (_get, set, url) => {
const response = await fetch(url)
set(countAtom, (await response.json()).count)
}
)

The write function (2nd arg) returns a promise, which will suspend.

We just need to make it synchronous and returns nothing, just like this:

const fetchCountAtom = atom(
(get) => get(countAtom),
(_get, set, url) => {
const fetchData = async () => {
const response = await fetch(url)
set(countAtom, (await response.json()).count)
}
fetchData()
}
)