Quick start
Choose the core package when you do not need a framework adapter.
Install
pnpm add @omni-async/core
pnpm add @omni-async/react
pnpm add @omni-async/vue
pnpm add @omni-async/svelte
Create an operation
import { createAsync } from "@omni-async/core";
const user = createAsync(
async ({ signal }, id: string) => {
const response = await fetch(`/api/users/${id}`, { signal: signal ?? undefined });
if (!response.ok) throw new Error("Unable to load user");
return response.json() as Promise<{ id: string; name: string }>;
},
{
abortable: true,
concurrency: "latest",
},
);
const unsubscribe = user.subscribe(() => {
console.log(user.getSnapshot());
});
await user.execute("42");
unsubscribe();
The snapshot moves from idle to loading, then to success or error. Calling reset() restores the initial snapshot; calling abort() invalidates active requests.
Use a framework adapter
The adapters provide the same operation as native reactive values. For example, React exposes a trigger and independent state fields:
import { useQuery } from "@omni-async/react";
function UserSearch() {
const user = useQuery(async (id: string) => {
const response = await fetch(`/api/users/${id}`);
if (!response.ok) throw new Error("Unable to load user");
return response.json() as Promise<{ name: string }>;
});
return (
<button disabled={user.loading} onClick={() => void user.trigger("42")}>
{user.data?.name ?? "Load user"}
</button>
);
}
See framework adapters for Vue and Svelte examples.