Vue
Reactive useStitch and useStitchStream composables backed by Vue 3 reactivity, over the framework-agnostic @stitchapi/query-core store — plus an optional TanStack Query adapter.
Use @stitchapi/vue when you call stitches from Vue 3 components and want the
call's lifecycle — pending / success / error, cancellation, refetch, and
streaming re-renders — managed for you. useStitch is the request/response
composable; useStitchStream re-renders as each delta chunk arrives, which is
the differentiator over plain request/response query libraries.
The composables are a thin layer over @stitchapi/query-core,
the framework-agnostic store that owns the reactive lifecycle. Vue mirrors each
snapshot into refs, so destructuring keeps reactivity and templates unwrap .value
for you.
Example
Install the composables, the store, core, and Vue:
npm install @stitchapi/vue @stitchapi/query-core stitchapi vuestitchapi and vue (^3.4) are peer dependencies; @tanstack/vue-query is an
optional peer, needed only for the queryOptions adapter below.
useStitch — request / response
Declare a stitch once, then drive it from a component. input may be a plain
value, a ref, or a getter — pass a getter (() => props.id) so the query
re-fetches when its structural key changes. Each returned field is a
ComputedRef, so destructuring keeps it reactive and the template unwraps .value
automatically:
<script setup lang="ts">
import { useStitch } from '@stitchapi/vue';
import { stitch } from 'stitchapi';
const props = defineProps<{ id: string }>();
const getUser = stitch({
baseUrl: 'https://api.example.com',
path: '/users/{id}',
});
const { data, isPending, isError, refetch } = useStitch(getUser, () => ({
params: { id: props.id },
}));
</script>
<template>
<Spinner v-if="isPending" />
<Retry v-else-if="isError" @click="refetch" />
<h1 v-else>{{ data?.name }}</h1>
</template>The query is re-created (and re-fetched) when the stitch's name or a structural
key of input changes. The in-flight run is aborted when the component's scope is
disposed (onScopeDispose).
useStitchStream — live deltas
For a streaming stitch (an sse or stream surface),
useStitchStream re-renders as each chunk arrives. chunks is the running list,
data is the accumulated array (mode: 'append', default) or the latest chunk
(mode: 'replace'), and status is 'streaming' until the terminal result,
then 'success':
<script setup lang="ts">
import { useStitchStream } from '@stitchapi/vue';
import { sse } from 'stitchapi/sse';
const props = defineProps<{ prompt: string }>();
const chat = sse({ url: 'https://api.example.com/chat' });
const { chunks, isStreaming } = useStitchStream(chat, () => ({
body: { prompt: props.prompt },
}));
</script>
<template>
<span v-for="(c, i) in chunks" :key="i">{{ c }}</span>
<Cursor v-if="isStreaming" />
</template>Both composables return the same shape — data, error, status, chunks, the
isPending / isError / isSuccess / isStreaming flags (each a ComputedRef),
plus refetch and cancel.
The shared store: @stitchapi/query-core
The composables hold almost no logic. All of it — running the call under an
AbortController, publishing status transitions, folding delta chunks into
state, cancel() by aborting, refetch() by re-running — lives in
@stitchapi/query-core's createStitchQuery, a subscribe / getSnapshot
handle with no framework imports and no node:*, so it is browser- and
edge-safe. Vue subscribes to it and reconciles each snapshot into a shallowRef:
import { } from '@stitchapi/query-core';
import { } from 'stitchapi';
import { } from 'zod';
const = ({
: 'https://api.example.com',
: '/users',
: .(.({ : .(), : .() })),
});
const = (, { : { : 'ada' } });
const = .(() => {
const = .();
if (.) .(.);
});Because the whole reactive lifecycle lives in the store and not the binding, the
React, Svelte, and Solid
bindings are the same few lines against their own reactive primitive — Vue's is
shallowRef + watch + onScopeDispose.
Optional: TanStack Query
Already on TanStack Query?
queryOptions(stitch, input) returns a plain { queryKey, queryFn } object you
pass straight to useQuery — it imports nothing from @tanstack/vue-query, so it
works even if you never install it:
<script setup lang="ts">
import { queryOptions } from '@stitchapi/vue';
import { useQuery } from '@tanstack/vue-query';
import { stitch } from 'stitchapi';
const getUser = stitch({
baseUrl: 'https://api.example.com',
path: '/users/{id}',
});
const { data } = useQuery(queryOptions(getUser, { params: { id: '7' } }));
</script>Reach for queryOptions when TanStack Query already owns your view state
and you want a stitch as the queryFn; reach for useStitch /
useStitchStream when you want StitchAPI to own the lifecycle directly —
especially for streaming, which useQuery does not model. See the TanStack
Query guide for how the two layers
split.
See also
React
Tearing-free useStitch and useStitchStream hooks built on useSyncExternalStore, over the framework-agnostic @stitchapi/query-core store — plus an optional TanStack Query adapter.
Svelte
stitchStore and stitchStreamStore — real Svelte stores wrapping a stitch call, over the framework-agnostic @stitchapi/query-core store. Works on Svelte 4 and 5, plus an optional TanStack Query adapter.