Skip to main content

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.

tip

Use in combination with a data-binding hook (useCache(), useSuspense(), useDLE(), useLive()) in another component.

MasterPost.vue
<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 StatusFetch.valueresolvedConditions
Invalidyes1pending promisefalsenot in store, deletion, invalidation
Staleyes1pending promisefalse(first-render, arg change) & expiry < now
Validnoresolved promisetruefetch completion
Errornorejected promisetruefetch failed
noundefinednull used as second argument

The returned Ref is updated with a new promise whenever a fetch is triggered: on argument change, invalidation, or reset.

note
  1. Identical fetches are automatically deduplicated

:::

Conditional Dependencies

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:

MasterPost.vue
<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>