From 53b37083c20df046e34f3b23d1a8a8ca015b0ee0 Mon Sep 17 00:00:00 2001 From: "BANO.notIT" Date: Sun, 1 Oct 2023 22:34:16 +0300 Subject: [PATCH 1/4] feat(async): deprecate reatomAsyncReaction in favor of reatomReactiveAsync --- packages/async/README.md | 20 +++++++++++-------- packages/async/src/index.test.ts | 2 +- packages/async/src/index.ts | 7 ++++++- ...on.test.ts => reatomReactiveAsync.test.ts} | 20 +++++++++---------- ...syncReaction.ts => reatomReactiveAsync.ts} | 18 +++++++++++++---- 5 files changed, 43 insertions(+), 24 deletions(-) rename packages/async/src/{reatomAsyncReaction.test.ts => reatomReactiveAsync.test.ts} (88%) rename packages/async/src/{reatomAsyncReaction.ts => reatomReactiveAsync.ts} (92%) diff --git a/packages/async/README.md b/packages/async/README.md index 6b6c7e440..f36119408 100644 --- a/packages/async/README.md +++ b/packages/async/README.md @@ -637,7 +637,7 @@ const reatomResource = (initState, url, concurrent = true) => { Check the real-world example in pooling example from [story tests below](https://www.reatom.dev/package/async#story-test) ([src](https://github.com/artalar/reatom/blob/v3/packages/async/src/index.story.test.ts)). -## reatomAsyncReaction +## reatomReactiveAsync This method is the simplest solution to describe an asynchronous resource that is based on local states. Let's delve into the problem. @@ -660,12 +660,12 @@ onConnect(fetchList.dataAtom, (ctx) => fetchList(ctx, ctx.get(pageAtom))) pageAtom.onChange(fetchSuggestion) // trigger ``` -`reatomAsyncReaction` allows us to use `ctx.spy` just like in the regular `atom`. It is much simpler, more obvious, and works automatically for both caching and previous request cancellation. +`reatomReactiveAsync` allows us to use `ctx.spy` just like in the regular `atom`. It is much simpler, more obvious, and works automatically for both caching and previous request cancellation. ```ts -import { reatomAsyncReaction } from '@reatom/async' +import { reatomReactiveAsync } from '@reatom/async' -const listReaction = reatomAsyncReaction(async (ctx) => { +const listReaction = reatomReactiveAsync(async (ctx) => { const page = ctx.spy(pageAtom) return request(`/api/list?page=${page}`, ctx.controller) }, 'listReaction') @@ -675,19 +675,23 @@ Now, `listReaction` has a `promiseAtom` that you can use with [useAtomPromise](h If you need to set up a default value and have the ability to use the resulting data, simply use `withDataAtom` as you would with any other async action. -But that's not all! The most powerful feature of `reatomAsyncReaction` is that you can use one `promiseAtom` in another, which greatly simplifies dependent request descriptions and prevents complex race conditions, as the stale promises are always automatically canceled. +But that's not all! The most powerful feature of `reatomReactiveAsync` is that you can use one `promiseAtom` in another, which greatly simplifies dependent request descriptions and prevents complex race conditions, as the stale promises are always automatically canceled. ```ts -import { reatomAsyncReaction } from '@reatom/async' +import { reatomReactiveAsync } from '@reatom/async' -const aReaction = reatomAsyncReaction(async (ctx) => { +const aReaction = reatomReactiveAsync(async (ctx) => { const page = ctx.spy(pageAtom) return request(`/api/a?page=${page}`, ctx.controller) }, 'aReaction') -const bReaction = reatomAsyncReaction(async (ctx) => { +const bReaction = reatomReactiveAsync(async (ctx) => { const a = ctx.spy(aReaction.promiseAtom) return request(`/api/b?a=${a}`, ctx.controller) }, 'bReaction') ``` In this example, `bReaction.pendingAtom` will be updated immediately as `aReaction` starts fetching! + +## reatomAsyncReaction + +> Deprecated: use [reatomReactiveAsync](#reatomreactiveasync) instead diff --git a/packages/async/src/index.test.ts b/packages/async/src/index.test.ts index 7c8f9032f..671f7caf4 100644 --- a/packages/async/src/index.test.ts +++ b/packages/async/src/index.test.ts @@ -19,7 +19,7 @@ import './index.story.test' import './withCache.test' import './withStatusesAtom.test' import './mapToAsync.test' -import './reatomAsyncReaction.test' +import './reatomReactiveAsync.test' test(`base API`, async () => { const fetchData = reatomAsync(async (ctx, v: number) => { diff --git a/packages/async/src/index.ts b/packages/async/src/index.ts index ca82d5751..a20a9a321 100644 --- a/packages/async/src/index.ts +++ b/packages/async/src/index.ts @@ -40,7 +40,12 @@ export type { AsyncStatuses, AsyncStatusesAtom, } from './withStatusesAtom' -export { reatomAsyncReaction, AsyncReaction } from './reatomAsyncReaction' +export { + reatomAsyncReaction, + AsyncReaction, + ReactiveAsync, + reatomReactiveAsync, +} from './reatomReactiveAsync' export interface AsyncAction extends Action> { diff --git a/packages/async/src/reatomAsyncReaction.test.ts b/packages/async/src/reatomReactiveAsync.test.ts similarity index 88% rename from packages/async/src/reatomAsyncReaction.test.ts rename to packages/async/src/reatomReactiveAsync.test.ts index 28d62b2f8..d14a874cf 100644 --- a/packages/async/src/reatomAsyncReaction.test.ts +++ b/packages/async/src/reatomReactiveAsync.test.ts @@ -2,21 +2,21 @@ import { suite } from 'uvu' import * as assert from 'uvu/assert' import { createTestCtx, mockFn } from '@reatom/testing' import { atom } from '@reatom/core' -import { reatomAsyncReaction } from './reatomAsyncReaction' +import { reatomReactiveAsync } from './reatomReactiveAsync' import { noop, sleep } from '@reatom/utils' import { withCache, withDataAtom, withErrorAtom, withRetry } from '.' import { isConnected } from '@reatom/hooks' -export const test = suite('reatomAsyncReaction') +export const test = suite('reatomReactiveAsync') test('base', async () => { const paramsAtom = atom(0, 'paramsAtom') - const async1 = reatomAsyncReaction(async (ctx) => { + const async1 = reatomReactiveAsync(async (ctx) => { const argument = ctx.spy(paramsAtom) await ctx.schedule(() => sleep()) return argument }, 'async1').promiseAtom - const async2 = reatomAsyncReaction(async (ctx) => { + const async2 = reatomReactiveAsync(async (ctx) => { const n = await ctx.spy(async1) return n }, 'async2').promiseAtom @@ -40,12 +40,12 @@ test('base', async () => { test('withCache', async () => { const sleepTrack = mockFn(sleep) const paramsAtom = atom(0, 'paramsAtom') - const aAtom = reatomAsyncReaction(async (ctx) => { + const aAtom = reatomReactiveAsync(async (ctx) => { const argument = ctx.spy(paramsAtom) await ctx.schedule(() => sleepTrack()) return argument }, 'aAtom').pipe(withCache()) - const bAtom = reatomAsyncReaction(async (ctx) => { + const bAtom = reatomReactiveAsync(async (ctx) => { const n = await ctx.spy(aAtom.promiseAtom) return n }, 'bAtom') @@ -77,7 +77,7 @@ test('withCache', async () => { test('controller', async () => { const controllerTrack = mockFn() const paramsAtom = atom(0, 'paramsAtom') - const someReaction = reatomAsyncReaction(async (ctx) => { + const someReaction = reatomReactiveAsync(async (ctx) => { const argument = ctx.spy(paramsAtom) ctx.controller.signal.addEventListener('abort', controllerTrack) await ctx.schedule(() => sleep()) @@ -103,7 +103,7 @@ test('controller', async () => { test('withDataAtom', async () => { const paramsAtom = atom(0, 'paramsAtom') - const someReaction = reatomAsyncReaction(async (ctx) => { + const someReaction = reatomReactiveAsync(async (ctx) => { const params = ctx.spy(paramsAtom) await ctx.schedule(() => sleep()) return params @@ -121,7 +121,7 @@ test('withDataAtom', async () => { test('withErrorAtom withRetry', async () => { let shouldThrow = true const paramsAtom = atom(123, 'paramsAtom') - const someReaction = reatomAsyncReaction(async (ctx) => { + const someReaction = reatomReactiveAsync(async (ctx) => { const params = ctx.spy(paramsAtom) if (shouldThrow) throw new Error('test error') await ctx.schedule(() => sleep()) @@ -153,7 +153,7 @@ test('withErrorAtom withRetry', async () => { test('abort should not stale', async () => { const paramsAtom = atom(123, 'paramsAtom') - const someReaction = reatomAsyncReaction(async (ctx) => { + const someReaction = reatomReactiveAsync(async (ctx) => { const params = ctx.spy(paramsAtom) await ctx.schedule(() => sleep()) return params diff --git a/packages/async/src/reatomAsyncReaction.ts b/packages/async/src/reatomReactiveAsync.ts similarity index 92% rename from packages/async/src/reatomAsyncReaction.ts rename to packages/async/src/reatomReactiveAsync.ts index e6432205f..38147ade1 100644 --- a/packages/async/src/reatomAsyncReaction.ts +++ b/packages/async/src/reatomReactiveAsync.ts @@ -14,10 +14,15 @@ import { merge, noop, throwIfAborted, toAbortError } from '@reatom/utils' import { reatomAsync, AsyncAction, ControlledPromise, AsyncCtx } from '.' import { isConnected, onConnect } from '@reatom/hooks' -export interface AsyncReaction extends AsyncAction<[], Resp> { +export interface ReactiveAsync extends AsyncAction<[], Resp> { promiseAtom: Atom> } +/** + * @deprecated use ReactiveAsync instead + */ +export interface AsyncReaction extends ReactiveAsync {} + export interface AsyncCtxSpy extends AsyncCtx { spy: { (anAtom: Atom): T @@ -26,10 +31,10 @@ export interface AsyncCtxSpy extends AsyncCtx { const resolved = new Set>() -export const reatomAsyncReaction = ( +export const reatomReactiveAsync = ( asyncComputed: (ctx: AsyncCtxSpy) => Promise, name = __count('asyncAtom'), -): AsyncReaction => { +): ReactiveAsync => { const promises = new CauseContext>() const dropCache = (ctx: Ctx) => @@ -164,7 +169,7 @@ export const reatomAsyncReaction = ( }, theAsync, { promiseAtom }, - ) as AsyncReaction + ) as ReactiveAsync Object.defineProperty(theAsync, '_handleCache', { get() { @@ -174,3 +179,8 @@ export const reatomAsyncReaction = ( return theReaction } + +/** + * @deprecated use reatomReactiveAsync instead + */ +export const reatomAsyncReaction = reatomReactiveAsync From 7267266ae2f43362dde98a66559e41bc2c7b56d4 Mon Sep 17 00:00:00 2001 From: "BANO.notIT" Date: Sun, 1 Oct 2023 22:34:44 +0300 Subject: [PATCH 2/4] docs(npm-react): use reatomReactiveAsync instead of reatomAsyncReaction --- packages/npm-react/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/npm-react/README.md b/packages/npm-react/README.md index f9fd5fc58..db94a9bf8 100644 --- a/packages/npm-react/README.md +++ b/packages/npm-react/README.md @@ -264,14 +264,14 @@ export const MyForm = () => { ## Use atom promise -If you have an atom with a promise and want to use its value directly, you could use `useAtomPromise`. This function relies on [React Suspense](https://react.dev/reference/react/Suspense) and throws the promise until it resolves. It can be useful with [reatomAsyncReaction](https://www.reatom.dev/package/async/#reatomasyncreaction). +If you have an atom with a promise and want to use its value directly, you could use `useAtomPromise`. This function relies on [React Suspense](https://react.dev/reference/react/Suspense) and throws the promise until it resolves. It can be useful with [reatomReactiveAsync](https://www.reatom.dev/package/async/#reatomreactiveasync). ```tsx -import { atom, reatomAsyncReaction } from '@reatom/framework' +import { atom, reatomReactiveAsync } from '@reatom/framework' import { useAtom, useAction, useAtomPromise } from '@reatom/npm-react' const pageAtom = atom(1, 'pageAtom') -const listReaction = reatomAsyncReaction(async (ctx) => { +const listReaction = reatomReactiveAsync(async (ctx) => { const page = ctx.spy(pageAtom) const response = await ctx.schedule(() => fetch(`/api/list?page=${page}`)) if (!response.ok) throw new Error(response.statusText) From 7e8bbf18a210473f239aacfe61e08ba3c68516cb Mon Sep 17 00:00:00 2001 From: "BANO.notIT" Date: Thu, 19 Oct 2023 20:45:41 +0300 Subject: [PATCH 3/4] test(async): use reatomReactiveAsync --- packages/async/src/reatomReactiveAsync.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/async/src/reatomReactiveAsync.test.ts b/packages/async/src/reatomReactiveAsync.test.ts index af81d2d84..565a43ea8 100644 --- a/packages/async/src/reatomReactiveAsync.test.ts +++ b/packages/async/src/reatomReactiveAsync.test.ts @@ -172,7 +172,7 @@ test('abort should not stale', async () => { test('direct retry', async () => { const paramsAtom = atom(123, 'paramsAtom') - const someReaction = reatomAsyncReaction(async (ctx) => { + const someReaction = reatomReactiveAsync(async (ctx) => { ctx.spy(paramsAtom) await ctx.schedule(() => calls++) }, 'someReaction') From 751d82224db62a38040ed2786f9d9b8fa3967f25 Mon Sep 17 00:00:00 2001 From: "BANO.notIT" Date: Thu, 19 Oct 2023 21:13:10 +0300 Subject: [PATCH 4/4] refactor(async): use reatomResource instead of reatomAsyncReaction --- packages/async/README.md | 18 +++++++-------- packages/async/src/index.test.ts | 2 +- packages/async/src/index.ts | 6 ++--- ...veAsync.test.ts => reatomResource.test.ts} | 22 +++++++++---------- ...atomReactiveAsync.ts => reatomResource.ts} | 16 +++++++------- packages/npm-react/README.md | 6 ++--- 6 files changed, 35 insertions(+), 35 deletions(-) rename packages/async/src/{reatomReactiveAsync.test.ts => reatomResource.test.ts} (88%) rename packages/async/src/{reatomReactiveAsync.ts => reatomResource.ts} (92%) diff --git a/packages/async/README.md b/packages/async/README.md index f36119408..e125ed6b9 100644 --- a/packages/async/README.md +++ b/packages/async/README.md @@ -637,7 +637,7 @@ const reatomResource = (initState, url, concurrent = true) => { Check the real-world example in pooling example from [story tests below](https://www.reatom.dev/package/async#story-test) ([src](https://github.com/artalar/reatom/blob/v3/packages/async/src/index.story.test.ts)). -## reatomReactiveAsync +## reatomResource This method is the simplest solution to describe an asynchronous resource that is based on local states. Let's delve into the problem. @@ -660,12 +660,12 @@ onConnect(fetchList.dataAtom, (ctx) => fetchList(ctx, ctx.get(pageAtom))) pageAtom.onChange(fetchSuggestion) // trigger ``` -`reatomReactiveAsync` allows us to use `ctx.spy` just like in the regular `atom`. It is much simpler, more obvious, and works automatically for both caching and previous request cancellation. +`reatomResource` allows us to use `ctx.spy` just like in the regular `atom`. It is much simpler, more obvious, and works automatically for both caching and previous request cancellation. ```ts -import { reatomReactiveAsync } from '@reatom/async' +import { reatomResource } from '@reatom/async' -const listReaction = reatomReactiveAsync(async (ctx) => { +const listReaction = reatomResource(async (ctx) => { const page = ctx.spy(pageAtom) return request(`/api/list?page=${page}`, ctx.controller) }, 'listReaction') @@ -675,16 +675,16 @@ Now, `listReaction` has a `promiseAtom` that you can use with [useAtomPromise](h If you need to set up a default value and have the ability to use the resulting data, simply use `withDataAtom` as you would with any other async action. -But that's not all! The most powerful feature of `reatomReactiveAsync` is that you can use one `promiseAtom` in another, which greatly simplifies dependent request descriptions and prevents complex race conditions, as the stale promises are always automatically canceled. +But that's not all! The most powerful feature of `reatomResource` is that you can use one `promiseAtom` in another, which greatly simplifies dependent request descriptions and prevents complex race conditions, as the stale promises are always automatically canceled. ```ts -import { reatomReactiveAsync } from '@reatom/async' +import { reatomResource } from '@reatom/async' -const aReaction = reatomReactiveAsync(async (ctx) => { +const aReaction = reatomResource(async (ctx) => { const page = ctx.spy(pageAtom) return request(`/api/a?page=${page}`, ctx.controller) }, 'aReaction') -const bReaction = reatomReactiveAsync(async (ctx) => { +const bReaction = reatomResource(async (ctx) => { const a = ctx.spy(aReaction.promiseAtom) return request(`/api/b?a=${a}`, ctx.controller) }, 'bReaction') @@ -694,4 +694,4 @@ In this example, `bReaction.pendingAtom` will be updated immediately as `aReacti ## reatomAsyncReaction -> Deprecated: use [reatomReactiveAsync](#reatomreactiveasync) instead +> Deprecated: use [reatomResource](#reatomresource) instead diff --git a/packages/async/src/index.test.ts b/packages/async/src/index.test.ts index 139ddd1f2..5b213b106 100644 --- a/packages/async/src/index.test.ts +++ b/packages/async/src/index.test.ts @@ -19,7 +19,7 @@ import './index.story.test' import './withCache.test' import './withStatusesAtom.test' import './mapToAsync.test' -import './reatomReactiveAsync.test' +import './reatomResource.test' test(`base API`, async () => { const fetchData = reatomAsync(async (ctx, v: number) => { diff --git a/packages/async/src/index.ts b/packages/async/src/index.ts index 3cbf04914..336529893 100644 --- a/packages/async/src/index.ts +++ b/packages/async/src/index.ts @@ -43,9 +43,9 @@ export type { export { reatomAsyncReaction, AsyncReaction, - ReactiveAsync, - reatomReactiveAsync, -} from './reatomReactiveAsync' + ResourceAtom, + reatomResource, +} from './reatomResource' export interface AsyncAction extends Action> { diff --git a/packages/async/src/reatomReactiveAsync.test.ts b/packages/async/src/reatomResource.test.ts similarity index 88% rename from packages/async/src/reatomReactiveAsync.test.ts rename to packages/async/src/reatomResource.test.ts index 565a43ea8..a5dbc13cb 100644 --- a/packages/async/src/reatomReactiveAsync.test.ts +++ b/packages/async/src/reatomResource.test.ts @@ -2,21 +2,21 @@ import { suite } from 'uvu' import * as assert from 'uvu/assert' import { createTestCtx, mockFn } from '@reatom/testing' import { atom } from '@reatom/core' -import { reatomReactiveAsync } from './reatomReactiveAsync' +import { reatomResource } from './reatomResource' import { noop, sleep } from '@reatom/utils' import { withCache, withDataAtom, withErrorAtom, withRetry } from '.' import { isConnected } from '@reatom/hooks' -export const test = suite('reatomReactiveAsync') +export const test = suite('reatomResource') test('base', async () => { const paramsAtom = atom(0, 'paramsAtom') - const async1 = reatomReactiveAsync(async (ctx) => { + const async1 = reatomResource(async (ctx) => { const argument = ctx.spy(paramsAtom) await ctx.schedule(() => sleep()) return argument }, 'async1').promiseAtom - const async2 = reatomReactiveAsync(async (ctx) => { + const async2 = reatomResource(async (ctx) => { const n = await ctx.spy(async1) return n }, 'async2').promiseAtom @@ -40,12 +40,12 @@ test('base', async () => { test('withCache', async () => { const sleepTrack = mockFn(sleep) const paramsAtom = atom(0, 'paramsAtom') - const aAtom = reatomReactiveAsync(async (ctx) => { + const aAtom = reatomResource(async (ctx) => { const argument = ctx.spy(paramsAtom) await ctx.schedule(() => sleepTrack()) return argument }, 'aAtom').pipe(withCache()) - const bAtom = reatomReactiveAsync(async (ctx) => { + const bAtom = reatomResource(async (ctx) => { const n = await ctx.spy(aAtom.promiseAtom) return n }, 'bAtom') @@ -77,7 +77,7 @@ test('withCache', async () => { test('controller', async () => { const controllerTrack = mockFn() const paramsAtom = atom(0, 'paramsAtom') - const someReaction = reatomReactiveAsync(async (ctx) => { + const someReaction = reatomResource(async (ctx) => { const argument = ctx.spy(paramsAtom) ctx.controller.signal.addEventListener('abort', controllerTrack) await ctx.schedule(() => sleep()) @@ -103,7 +103,7 @@ test('controller', async () => { test('withDataAtom', async () => { const paramsAtom = atom(0, 'paramsAtom') - const someReaction = reatomReactiveAsync(async (ctx) => { + const someReaction = reatomResource(async (ctx) => { const params = ctx.spy(paramsAtom) await ctx.schedule(() => sleep()) return params @@ -121,7 +121,7 @@ test('withDataAtom', async () => { test('withErrorAtom withRetry', async () => { let shouldThrow = true const paramsAtom = atom(123, 'paramsAtom') - const someReaction = reatomReactiveAsync(async (ctx) => { + const someReaction = reatomResource(async (ctx) => { const params = ctx.spy(paramsAtom) if (shouldThrow) throw new Error('test error') await ctx.schedule(() => sleep()) @@ -155,7 +155,7 @@ test('withErrorAtom withRetry', async () => { test('abort should not stale', async () => { const paramsAtom = atom(123, 'paramsAtom') - const someReaction = reatomReactiveAsync(async (ctx) => { + const someReaction = reatomResource(async (ctx) => { const params = ctx.spy(paramsAtom) await ctx.schedule(() => sleep()) return params @@ -172,7 +172,7 @@ test('abort should not stale', async () => { test('direct retry', async () => { const paramsAtom = atom(123, 'paramsAtom') - const someReaction = reatomReactiveAsync(async (ctx) => { + const someReaction = reatomResource(async (ctx) => { ctx.spy(paramsAtom) await ctx.schedule(() => calls++) }, 'someReaction') diff --git a/packages/async/src/reatomReactiveAsync.ts b/packages/async/src/reatomResource.ts similarity index 92% rename from packages/async/src/reatomReactiveAsync.ts rename to packages/async/src/reatomResource.ts index 6729abfb0..b1aeb521a 100644 --- a/packages/async/src/reatomReactiveAsync.ts +++ b/packages/async/src/reatomResource.ts @@ -13,14 +13,14 @@ import { merge, noop, toAbortError } from '@reatom/utils' import { reatomAsync, AsyncAction, ControlledPromise, AsyncCtx } from '.' import { isConnected, onConnect } from '@reatom/hooks' -export interface ReactiveAsync extends AsyncAction<[], Resp> { +export interface ResourceAtom extends AsyncAction<[], Resp> { promiseAtom: Atom> } /** - * @deprecated use ReactiveAsync instead + * @deprecated use ResourceAtom instead */ -export interface AsyncReaction extends ReactiveAsync {} +export interface AsyncReaction extends ResourceAtom {} export interface AsyncCtxSpy extends AsyncCtx { spy: { @@ -30,10 +30,10 @@ export interface AsyncCtxSpy extends AsyncCtx { const resolved = new Set>() -export const reatomReactiveAsync = ( +export const reatomResource = ( asyncComputed: (ctx: AsyncCtxSpy) => Promise, name = __count('asyncAtom'), -): ReactiveAsync => { +): ResourceAtom => { const promises = new CauseContext>() const dropCache = (ctx: Ctx) => @@ -161,7 +161,7 @@ export const reatomReactiveAsync = ( }, theAsync, { promiseAtom }, - ) as ReactiveAsync + ) as ResourceAtom Object.defineProperty(theAsync, '_handleCache', { get() { @@ -173,6 +173,6 @@ export const reatomReactiveAsync = ( } /** - * @deprecated use reatomReactiveAsync instead + * @deprecated use reatomResource instead */ -export const reatomAsyncReaction = reatomReactiveAsync +export const reatomAsyncReaction = reatomResource diff --git a/packages/npm-react/README.md b/packages/npm-react/README.md index db94a9bf8..d944a6e7a 100644 --- a/packages/npm-react/README.md +++ b/packages/npm-react/README.md @@ -264,14 +264,14 @@ export const MyForm = () => { ## Use atom promise -If you have an atom with a promise and want to use its value directly, you could use `useAtomPromise`. This function relies on [React Suspense](https://react.dev/reference/react/Suspense) and throws the promise until it resolves. It can be useful with [reatomReactiveAsync](https://www.reatom.dev/package/async/#reatomreactiveasync). +If you have an atom with a promise and want to use its value directly, you could use `useAtomPromise`. This function relies on [React Suspense](https://react.dev/reference/react/Suspense) and throws the promise until it resolves. It can be useful with [reatomResource](https://www.reatom.dev/package/async/#reatomresource). ```tsx -import { atom, reatomReactiveAsync } from '@reatom/framework' +import { atom, reatomResource } from '@reatom/framework' import { useAtom, useAction, useAtomPromise } from '@reatom/npm-react' const pageAtom = atom(1, 'pageAtom') -const listReaction = reatomReactiveAsync(async (ctx) => { +const listReaction = reatomResource(async (ctx) => { const page = ctx.spy(pageAtom) const response = await ctx.schedule(() => fetch(`/api/list?page=${page}`)) if (!response.ok) throw new Error(response.statusText)