Receber por email
← Voltar para o catálogo

pinia-colada

Pinia Colada data fetching for Vue/Nuxt with useQuery, useMutation. Use for async state, query cache, SSR, or encountering invalidation, hydration, TanStack Vue Query migration errors.

178estrelas
Atualizado há 5 meses

Ver no GitHub ↗ Licença: MIT

Como adicionar

/plugin marketplace add secondsky/claude-skills

O comando exato pode variar conforme o repositório. Confira o README no GitHub.

Para o autor da skill

Cole no README do seu repo

Mostra que sua skill está catalogada na Skillteca, gera backlink e tráfego rastreável.

[![Skillteca](https://www.skillteca.com.br/api/badge/pinia-colada/svg)](https://www.skillteca.com.br/skills/pinia-colada)

Alerta por categoria

Receba novas skills de Design e Frontend toda segunda

1 email curto, só com as skills novas de Design e Frontend. 4 minutos de leitura, sem spam, cancela com 1 clique.

Você confirma o email no primeiro envio. Sem spam. Cancela com 1 clique.

Ler descrição completa

Pinia Colada - Smart Data Fetching for Vue

Status: Production Ready ✅ | Last Updated: 2025-11-28 Latest Version: @pinia/colada@0.17.9 | Dependencies: Vue 3.5.17+, Pinia 2.2.6+ or 3.0+

Quick Start (5 Minutes)

1. Install Dependencies

For Vue Projects:

bun add @pinia/colada pinia  # preferred
# or: bun add @pinia/colada pinia

For Nuxt Projects:

bun add @pinia/nuxt @pinia/colada-nuxt  # install both Pinia and Pinia Colada modules
# or: bun add @pinia/nuxt @pinia/colada-nuxt

Why this matters:

  • Pinia Colada requires Pinia 2.2.6+ or 3.0+ as peer dependency
  • Nuxt module handles SSR serialization automatically
  • Vue 3.5.17+ required for optimal reactivity

2. Set Up Pinia Colada Plugin

For Vue Projects:

// src/main.ts
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import { PiniaColada } from '@pinia/colada'
import App from './App.vue'

const app = createApp(App)
const pinia = createPinia()

app.use(pinia)
app.use(PiniaColada, {
  // Optional: Configure defaults
  query: {
    staleTime: 5000,        // 5 seconds
    gcTime: 5 * 60 * 1000,  // 5 minutes (garbage collection)
    refetchOnMount: true,
    refetchOnWindowFocus: false,
  },
})

app.mount('#app')

For Nuxt Projects:

// nuxt.config.ts
export default defineNuxtConfig({
  modules: [
    '@pinia/nuxt',           // Must be before @pinia/colada-nuxt
    '@pinia/colada-nuxt',
  ],

  // Optional: Configure Pinia Colada
  piniaColada: {
    query: {
      staleTime: 5000,
      gcTime: 5 * 60 * 1000,
    },
  },
})

CRITICAL:

  • For Nuxt: @pinia/nuxt must be listed before @pinia/colada-nuxt
  • Plugin must be registered after Pinia instance
  • Configuration is optional - sensible defaults provided

3. Create First Query

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

interface Todo {
  id: number
  title: string
  completed: boolean
}

async function fetchTodos(): Promise<Todo[]> {
  const response = await fetch('/api/todos')
  if (!response.ok) {
    throw new Error('Failed to fetch todos')
  }
  return response.json()
}

const {
  data,       // Ref<Todo[] | undefined>
  isPending,  // Ref<boolean> - initial loading
  isLoading,  // Ref<boolean> - any loading (including refetch)
  error,      // Ref<Error | null>
  refresh,    // () => Promise<void> - manual refetch
} = useQuery({
  key: ['todos'],
  query: fetchTodos,
})
</script>

<template>
  <div>
    <div v-if="isPending">Loading todos...</div>
    <div v-else-if="error">Error: {{ error.message }}</div>
    <ul v-else-if="data">
      <li v-for="todo in data" :key="todo.id">
        {{ todo.title }}
      </li>
    </ul>
  </div>
</template>

CRITICAL:

  • Query key must be an array (or getter returning array) for consistent caching
  • Query query is the async function that fetches data
  • Throw errors in query function for proper error handling
  • isPending is true only on initial load, isLoading includes refetches

4. Create First Mutation

<script setup lang="ts">
import { useMutation, useQueryCache } from '@pinia/colada'

interface NewTodo {
  title: string
}

async function createTodo(newTodo: NewTodo) {
  const response = await fetch('/api/todos', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(newTodo),
  })
  if (!response.ok) throw new Error('Failed to create todo')
  return response.json()
}

const queryCache = useQueryCache()

const {
  mutate,        // (variables: NewTodo) => Promise<void>
  mutateAsync,   // (variables: NewTodo) => Promise<Result>
  isPending,     // Ref<boolean>
  error,         // Ref<Error | null>
  data,          // Ref<Result | undefined>
} = useMutation({
  mutation: createTodo,

  // Invalidate todos query after mutation succeeds
  async onSettled({ id }) {
    await queryCache.invalidateQueries({ key: ['todos'] })
  },
})

function handleAddTodo(title: string) {
  mutate({ title })
}
</script>

<template>
  <form @submit.prevent="handleAddTodo(newTitle)">
    <input v-model="newTitle" required />
    <button type="submit" :disabled="isPending">
      {{ isPending ? 'Adding...' : 'Add Todo' }}
    </button>
    <div v-if="error">Error: {{ error.message }}</div>
  </form>
</template>

Why this works:

  • onSettled runs after success or error, perfect for invalidation
  • invalidateQueries marks matching queries as stale and refetches active ones
  • mutate is fire-and-forget, mutateAsync returns Promise for await
  • Mutations don't cache by default (correct behavior for writes)

Critical Rules

Always Do

✅ Include all variables used in query function in the key ✅ Throw errors in query/mutation functions for proper error handling ✅ Use useQueryCache() for invalidation in mutations ✅ Use isPending for initial load, isLoading for any loading state ✅ Await invalidateQueries() in onSettled when you need data fresh before continuing ✅ Use placeholderData for paginated queries to avoid flashing ✅ Snapshot cache with getQueryData before optimistic updates ✅ Return context from onMutate for rollback in onError ✅ Configure staleTime and gcTime at plugin level for app-wide defaults ✅ Use reusable composables for queries instead of inline useQuery

Never Do

❌ Never use plain strings as keys - always use arrays ❌ Never return undefined from query function - throw errors instead ❌ Never mutate data.value directly - it's readonly ❌ Never forget to invalidate related queries after mutations ❌ Never use onSuccess in queries (not available, use watch instead) ❌ Never forget to await mutateAsync() - it returns a Promise ❌ Never skip cancelQueries before optimistic updates (causes race conditions) ❌ Never use getQueryData without checking for undefined ❌ Never invalidate queries in onMutate (do it in onSettled) ❌ Never hardcode URLs - use environment variables for API base URLs

Top 5 Errors Prevention

This skill prevents 12 documented errors. Here are the top 5:

Error #1: Query Not Refetching After Mutation

Error: Data doesn't update in UI after successful mutation Prevention: Always use invalidateQueries in onSettled:

useMutation({
  mutation: createTodo,
  async onSettled() {
    await queryCache.invalidateQueries({ key: ['todos'] })
  },
})

See: references/error-catalog.md #1

Error #2: Race Condition with Optimistic Updates

Error: Optimistic update gets overwritten by in-flight request Prevention: Always call cancelQueries in onMutate:

onMutate(id) {
  cache.cancelQueries({ key: ['todos'] })
  // Then do optimistic update
}

See: references/error-catalog.md #2

Error #3: SSR Hydration Mismatch

Error: Hydration completed but contains mismatches Prevention: Set refetchOnMount: false for SSR queries

useQuery({
  key: ['todos'],
  query: fetchTodos,
  refetchOnMount: false, // Prevents SSR hydration mismatch
})

See: references/error-catalog.md #3

Error #4: Query Key Not Reactive

Error: Query doesn't refetch when variable changes Prevention: Use function for reactive keys:

// ❌ Wrong - static key
key: ['todos', id.value]

// ✅ Correct - reactive key
key: () => ['todos', id.value]

See: references/error-catalog.md #4

Error #5: Nuxt Module Order Wrong

Error: PiniaColada plugin not found or SSR errors Prevention: Always put @pinia/nuxt first:

export default defineNuxtConfig({
  modules: [
    '@pinia/nuxt',           // MUST be first
    '@pinia/colada-nuxt',    // Then Colada
  ],
})

See: references/error-catalog.md #10

For complete error catalog (all 12 errors): See references/error-catalog.md

Using Bundled Resources

References (references/)

Detailed guides loaded when needed:

  • **`referenc
Compartilhar X LinkedIn