Vue

Install the adapter alongside Vue 3.2 or newer:

pnpm add @omni-async/vue @vue/runtime-core

Query

<script setup lang="ts">
import { useQuery } from "@omni-async/vue";

const users = useQuery(
  async (team: string) => {
    const response = await fetch(`/api/teams/${team}/users`);
    if (!response.ok) throw new Error("Unable to load users");
    return response.json() as Promise<string[]>;
  },
  { initial: () => [] },
);
</script>

<template>
  <button :disabled="users.loading.value" @click="users.trigger('platform')">Load users</button>
</template>

The result fields are Vue refs. useAsync invalidates active requests when its current effect scope is disposed.

Shared data ref

Vue queries can write into an existing ref:

const query = useQuery(loadUsers, {
  data: shallowRef<User[]>([]),
});

query.data.value.push(newUser);
await query.trigger();

query.data is the exact writable ref passed in data. Manual changes are immediately visible, an accepted successful request replaces its value, and a rejected request preserves its current value. A later success can therefore overwrite manual edits.

The provided ref is the query's data storage, including after manual changes. Use initial instead when the composable should own read-only computed data.