Skip to content

Data Fetching

Kimesh integrates with TanStack Query to provide powerful data loading patterns. Data can be prefetched in route loaders so it's ready before navigation completes.

The Pattern

  1. Define query options in a data file
  2. Prefetch in the route loader with queryClient.ensureQueryData()
  3. Use useQuery() in the component — data is already cached

Quick Example

Define Queries

ts
// routes/posts/-posts.data.ts
import { defineQueryOptions, createQueryKeyFactory } from '@kimesh/query'

export const postKeys = createQueryKeyFactory('posts', {
  list: null,
  detail: (id: string) => id,
})

export const postsListQuery = defineQueryOptions({
  key: postKeys.list(),
  query: () => fetch('/api/posts').then(r => r.json()),
  staleTime: 5 * 60 * 1000,
})

export const postDetailQuery = (id: string) =>
  defineQueryOptions({
    key: postKeys.detail(id),
    query: () => fetch(`/api/posts/${id}`).then(r => r.json()),
  })

Prefetch in Loader

vue
<!-- routes/posts/index.vue -->
<script lang="ts">
import { postsListQuery } from './-posts.data'

// createFileRoute is auto-imported
export const Route = createFileRoute('/posts')({
  loader: async ({ context }) => {
    await context.queryClient.ensureQueryData(postsListQuery)
  },
})
</script>

<script setup lang="ts">
import { postsListQuery } from './-posts.data'

// useQuery is auto-imported — data already cached!
const { data: posts } = useQuery(postsListQuery)
</script>

<template>
  <article v-for="post in posts" :key="post.id">
    <h2>{{ post.title }}</h2>
  </article>
</template>

Nuxt-style Composables

Kimesh also provides Nuxt-style data fetching composables:

useKmFetch

vue
<script setup>
// Auto-imported
const { data, pending, error, refresh } = useKmFetch('/api/posts')
</script>

useKmAsyncData

vue
<script setup>
const { data, pending, error } = useKmAsyncData('posts', () =>
  fetch('/api/posts').then(r => r.json())
)
</script>

Lazy Variants

useLazyKmFetch and useLazyKmAsyncData don't block navigation — they fetch in the background.

$fetch

The global $fetch utility provides a layer-aware fetch client:

ts
// Auto-imported
const posts = await $fetch('/api/posts')
const post = await $fetch('/api/posts/1', {
  method: 'POST',
  body: { title: 'New Post' },
})

Suspense & Deferred Loading

For progressive loading with skeleton UI:

ts
import { defer } from '@kimesh/query'

export const Route = createFileRoute('/users/:id')({
  loader: async ({ params, context }) => {
    // Critical: blocks navigation
    await context.queryClient.ensureQueryData(userQuery(params.id))
    // Deferred: loads progressively
    defer(context.queryClient, userActivityQuery(params.id))
  },
})
vue
<template>
  <!-- Renders immediately -->
  <UserHeader :user="user" />

  <!-- Progressive loading with KmDeferred -->
  <KmDeferred>
    <UserActivity :user-id="user.id" />
    <template #fallback>
      <ActivitySkeleton />
    </template>
    <template #error="{ error, retry }">
      <p>{{ error.message }}</p>
      <button @click="retry">Retry</button>
    </template>
  </KmDeferred>
</template>

Next Steps

Released under the MIT License.