useFetch()
Fetch an Endpoint if it is not in cache or stale. Returns a Ref
holding the fetch promise (with a resolved flag). A new fetch is triggered when the arguments change or
the data is invalidated. Use it to start fetches early, then read the data
with useSuspense(), useCache() or useDLE().
Usage
Parallel data loading
await useSuspense() runs sequentially in <script setup>. Calling useFetch() for each endpoint first
starts every fetch in parallel; the following useSuspense() calls then reuse the in-flight requests.
<script setup lang="ts"> import { useFetch, useSuspense } from '@data-client/vue'; import { PostResource, CommentResource } from './Resources'; const props = defineProps<{ id: number }>(); // Both fetches start in parallel useFetch(PostResource.get, { id: props.id }); useFetch(CommentResource.getList, { postId: props.id }); // useSuspense() reads the results — the second fetch // is already in-flight while the first one is awaited const post = await useSuspense(PostResource.get, { id: props.id }); const comments = await useSuspense(CommentResource.getList, { postId: props.id, }); </script> <template> <article> <h3>{{ post.title }}</h3> <p>{{ post.body }}</p> <h4>Comments</h4> <div v-for="comment in comments" :key="comment.id" class="listItem"> <strong>{{ comment.author }}</strong>: {{ comment.text }} </div> </article> </template>
Prefetching
useFetch() can also be used standalone to ensure resources are available early in a render tree before they are needed.
Use in combination with a data-binding hook (useCache(), useSuspense(), useDLE(), useLive()) in another component.
<script setup lang="ts">
import { useFetch } from '@data-client/vue';
import { PostResource } from './Resources';
const props = defineProps<{ id: number }>();
useFetch(PostResource.get, { id: props.id });
// ...
</script>
Behavior
| Expiry Status | Fetch | .value | resolved | Conditions |
|---|---|---|---|---|
| Invalid | yes1 | pending promise | false | not in store, deletion, invalidation |
| Stale | yes1 | pending promise | false | (first-render, arg change) & expiry < now |
| Valid | no | resolved promise | true | fetch completion |
| Error | no | rejected promise | true | fetch failed |
| no | undefined | null used as second argument |
The returned Ref is updated with a new promise whenever a fetch is triggered: on argument change,
invalidation, or reset.
- Identical fetches are automatically deduplicated
:::
Use null as the second argument to any Data Client hook means "do nothing."
// todo could be undefined if id is undefined
const todo = useFetch(
TodoResource.get,
computed(() => (id.value ? { id: id.value } : null)),
);
Types
function useFetch(
endpoint: ReadEndpoint,
...args: MaybeRefsOrGetters<Parameters<typeof endpoint>> | [null]
): Ref<
| (Promise<Denormalize<typeof endpoint.schema>> & { resolved: boolean })
| undefined
>;
Arguments can be plain values or refs (including computed); a new fetch is triggered when they change.
Examples
Checking fetch status
Use promise.resolved to check whether data is still loading:
<script setup lang="ts">
import { useFetch } from '@data-client/vue';
import { PostResource } from './Resources';
const props = defineProps<{ id: number }>();
const promise = useFetch(PostResource.get, { id: props.id });
if (promise.value && !promise.value.resolved) {
// fetch is in-flight
}
// ...
</script>