Make a detail page feel instant after clicking from a list/grid:
Use the supported primitives together:
getQueryKey(...)useNuxtData(...)useConvexQuery(..., { default })getQueryKey is intentionally not auto-imported. Use an explicit import from better-convex-nuxt/composables.
<script setup lang="ts">
import { api } from '~~/convex/_generated/api'
const { data: posts } = await useConvexQuery(api.posts.list, {})
</script>
<script setup lang="ts">
import { api } from '~~/convex/_generated/api'
import { getQueryKey } from 'better-convex-nuxt/composables'
const route = useRoute()
const slug = computed(() => route.params.slug as string)
const listCacheKey = getQueryKey(api.posts.list, {})
const { data: cachedPosts } = useNuxtData(listCacheKey)
const cachedCard = computed(() => cachedPosts.value?.find((post) => post.slug === slug.value))
const { data: post } = await useConvexQuery(
api.posts.getBySlug,
computed(() => ({ slug: slug.value })),
{
default: () =>
cachedCard.value
? {
title: cachedCard.value.title,
description: cachedCard.value.description,
content: null,
}
: undefined,
transform: (fullPost) =>
fullPost
? {
title: fullPost.title,
description: fullPost.description,
content: fullPost.content,
}
: null,
},
)
</script>
useNuxtData)getQueryKey)useConvexCachedThere is a working playground version of this pattern at:
/labs/query-features/cache-reuseIt uses a slug-shaped route ([slug].vue) and shows whether the detail page is currently rendering: