mcpField
P
pinia-colada-skilld

pinia-colada-skilld

github.com/skilld-devDevelopment184238 installsUpdated 3w ago
Repository

About pinia-colada-skilld

pinia-colada-skilld is a reference skill for @pinia/colada, a data-fetching layer for Vue built on Pinia. It covers cached queries, mutations, shared query state, and cache management for Vue developers.

Key features

  1. 01Cached data queries with reactive keys
  2. 02Mutations and query invalidation
  3. 03Shared query state with defineQuery
  4. 04Typed reusable query options
  5. 05Cache management and infinite queries

Use cases

  1. 01Fetching data that depends on route parameters
  2. 02Refreshing cached queries after mutations
  3. 03Sharing query state across components
  4. 04Building paginated data views

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/skilld-dev/vue-ecosystem-skills --skill pinia-colada-skilld

After installing, type/pinia-colada-skilldin Claude Code to confirm it loaded.

Bundled files

References and scripts installed along with SKILL.md.

references/
infinite-queries.md
migration.md
mutations.md
plugins.md
queries.md
query-cache.md
ssr.md

Details

From the project README

@pinia/colada 1.4.5

The smart data fetching layer for Vue.js, built on Pinia. Queries read and cache data (useQuery), mutations write data (useMutation), everything lives in Pinia stores (useQueryCache, useMutationCache).

  • Docs: https://pinia-colada.esm.dev
  • API types: dist/index.d.mts in the prepared package source
  • Runtime exports: dist/index.mjs:1487
  • Peers: vue ^3.5.41, pinia ^2.2.6 || ^3.0.0 || ^4.0.2 (pinia 4 allowed since 1.4.1, package.json:91-94)
  • Bundled codemods: codemods/rules/*.yaml in the package

Setup

npm install pinia @pinia/colada
import { createPinia } from 'pinia'
import { PiniaColada } from '@pinia/colada'

const app = createApp(App)
app.use(createPinia())
// install after pinia; the options object is required for correct typing
app.use(PiniaColada, {
  queryOptions: { staleTime: 60_000 },
  plugins: [],
})

Global options go under queryOptions / mutationOptions (dist/index.d.mts:1601-1618).

Mental model

  • A query is identified by its key: a JSON-serializable array (EntryKey, dist/index.d.mts:119). Keys are hierarchical: { key: ['todos'] } also matches ['todos', { filter: 'done' }] when filtering.
  • status is the data status: 'pending' | 'success' | 'error'. asyncStatus is the operation status: 'idle' | 'loading'. They are separate on purpose (https://pinia-colada.esm.dev/guide/queries.md).
  • Defaults: staleTime: 5000, gcTime: 300_000, refetchOnMount, refetchOnWindowFocus, refetchOnReconnect, enabled: true (dist/index.mjs:92-97). Mutation gcTime default is 60_000 (dist/index.d.mts:1379).

Core patterns

Basic query
<script setup lang="ts">
import { useQuery } from '@pinia/colada'

const { state, asyncStatus } = useQuery({
  key: ['todos'],
  query: () => fetch('/api/todos').then(res => res.json()),
})
</script>

<template>
  <div v-if="state.status === 'pending'">Loading...</div>
  <div v-else-if="state.status === 'error'">{{ state.error.message }}</div>
  <ul v-else>
    <li v-for="todo in state.data" :key="todo.id">{{ todo.text }}</li>
  </ul>
</template>

Use the grouped state object for type narrowing in templates. TypeScript cannot narrow separate data / error refs from status (https://pinia-colada.esm.dev/guide/queries.md).

Reactive keys: pass a getter

Everything the query function reads (route params, refs) must be in the key. Pass key as a getter so the query refetches when dependencies change:

const { data } = useQuery({
  key: () => ['contacts', route.params.id as string],
  query: () => fetch(`/api/contacts/${route.params.id}`).then(r => r.json()),
})
Guard queries with enabled

Prevent invalid fetches when a required param is absent (common in stores and global queries):

useQuery({
  key: () => ['decks', route.params.deckId],
  query: () => fetchDeck(route.params.deckId as string),
  enabled: () => 'deckId' in route.params,
})
Type-safe shared options: defineQueryOptions
export const todoOptions = defineQueryOptions((id: string) => ({
  key: ['todos', id],
  query: () => fetchTodo(id),
}))

// single-function form; the returned key is tagged so queryCache infers TData
const { data } = useQuery(() => todoOptions(route.params.id as string))
const todo = queryCache.getQueryData(todoOptions('1').key) // typed

useQuery accepts options or a getter returning options (dist/index.d.mts:733). Since 1.0 the two-parameter form useQuery(options, paramsGetter) is removed; see references/migration.md.

Shared query state: defineQuery

Wrap queries used by multiple components so refs are created once, like a tiny Pinia store. The setup function must be synchronous:

export const useFilteredTodos = defineQuery(() => {
  const search = ref('')
  const query = useQuery({
    key: () => ['todos', { search: search.value }],
    query: () => fetchTodos(search.value),
  })
  return { ...query, search }
})

Details: references/queries.md.

Mutation + invalidation
const queryCache = useQueryCache()

const { mutate, isLoading } = useMutation({
  mutation: (text: string) => createTodo(text),
  async onSettled() {
    await queryCache.invalidateQueries({ key: ['todos'] })
  },
})
  • mutate(vars) never rejects; use it in templates and event handlers.
  • mutateAsync(vars) returns a promise and rejects on failure.
  • Put onMutate before mutation in the options object so its returned context is inferred in later hooks (dist/index.d.mts:1410-1433).
  • Optimistic updates: write to the cache in onMutate, roll back in onError only if the cache still holds your optimistic value. Full pattern in references/mutations.md.
Queries have no onSuccess/onError

This is intentional: a query can have many watchers. Use watch(data, ...), or global hooks via PiniaColadaQueryHooksPlugin (https://pinia-colada.esm.dev/plugins/official/query-hooks.md).

Version-critical rules (1.x)

  • useQuery(setup, paramsGetter) and useQueryState(setup, paramsGetter) were removed in 1.0.0. Migrate with the shipped codemod: ast-grep scan -r node_modules/@pinia/colada/codemods/rules/migration-0-21-to-1-0.yaml -i src (https://github.com/posva/pinia-colada/blob/main/CHANGELOG.md).
  • useQueryState(key) reads query state without fetching; the key is the only argument (dist/index.d.mts:920-926).
  • initialData changes query state to success; placeholderData does not change the cache (dist/index.d.mts:558-600).
  • To reset an entry's state manually use queryCache.setEntryState(entry, state); setting data to undefined via setQueryData() no longer resets state.
  • Infinite query data is { pages, pageParams }; use setInfiniteQueryData() (added 1.2.0), not setQueryData(), to prime infinite entries.
  • Devtools are a separate package: @pinia/colada-devtools.
  • Nuxt: install the @pinia/colada-nuxt module; it handles SSR serialization automatically.

References

  • queries.md: useQuery API, options, return values, useQueryState, defineQuery, defineQueryOptions, key factories
  • mutations.md: useMutation API, hooks and context, optimistic updates, defineMutation, defineMutationOptions
  • infinite-queries.md: useInfiniteQuery, defineInfiniteQueryOptions, setInfiniteQueryData, maxPages
  • query-cache.md: cache stores, invalidation, filters, manual cache writes, error codes
  • plugins.md: plugin API, PiniaColadaQueryHooksPlugin, TypesConfig augmentation, official plugin packages
  • ssr.md: serialization and hydration, lazy queries, PiniaColadaSSRNoGc
  • migration.md: 0.x to 1.x changes and codemods

Comments

Markdown supported