关于 pinia-colada
pinia-colada 是面向 Vue 3 和 Nuxt 开发者的 Pinia 数据获取技能,提供查询、缓存与变更的实现指导。它还整理了常见错误、SSR 设置和可复用模式。
主要功能
- 01查询与响应式缓存
- 02变更及查询失效
- 03乐观更新与回滚
- 04分页、轮询和预取模式
- 05Nuxt SSR 配置指导
- 06错误排查参考
适用场景
- 01为待办列表实现 CRUD 数据流
- 02构建带占位数据的分页表格
- 03为变更操作添加乐观更新
- 04在 Nuxt 应用中配置 SSR 数据获取
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ secondsky/ claude-skills --skill pinia-colada安装后在 Claude Code 中输入/pinia-colada确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/common-patterns.mdconfiguration.mderror-catalog.mdmigration-from-tanstack-vue-query.mdsetup-guide.md详细介绍
Pinia Colada——为 Vue 提供智能数据获取
状态:已可用于生产环境 ✅ | 上次更新:2025-11-28 最新版本:@pinia/[email protected] | 依赖项:Vue 3.5.17+、Pinia 2.2.6+ 或 3.0+
快速入门(5 分钟)
1. 安装依赖
适用于 Vue 项目:
bun add @pinia/colada pinia # preferred
# or: bun add @pinia/colada pinia
适用于 Nuxt 项目:
bun add @pinia/nuxt @pinia/colada-nuxt # install both Pinia and Pinia Colada modules
# or: bun add @pinia/nuxt @pinia/colada-nuxt
原因:
- Pinia Colada 需要 Pinia 2.2.6+ 或 3.0+ 作为对等依赖
- Nuxt 模块会自动处理 SSR 序列化
- 为获得最佳响应性,需要 Vue 3.5.17+
2. 设置 Pinia Colada 插件
适用于 Vue 项目:
// 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')
适用于 Nuxt 项目:
// 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,
},
},
})
重要:
- 对于 Nuxt:
@pinia/nuxt必须列在@pinia/colada-nuxt之前 - 必须在 Pinia 实例之后注册插件
- 配置是可选的——已提供合理的默认值
3. 创建第一个查询
<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>
重要:
- 查询
key必须是数组(或返回数组的 getter),以确保缓存一致 - 查询
query是用于获取数据的异步函数 - 在查询函数中抛出错误,以便正确处理错误
isPending仅在初次加载时为true,isLoading则包含重新获取数据的情况
4. 创建第一个变更
<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>
这样做的原因:
onSettled会在成功或出错后运行,非常适合用于失效处理invalidateQueries会将匹配的查询标记为过期,并重新获取活跃查询的数据mutate会触发操作但不等待结果,mutateAsync会返回 Promise,供await使用- 默认情况下,变更不会缓存(这是写入操作的正确行为)
关键规则
务必做到
✅ 将查询函数中使用的所有变量都包含在 key 中
✅ 在查询/变更函数中抛出错误,以便正确处理错误
✅ 在变更操作中使用 useQueryCache() 进行失效处理
✅ 初次加载时使用 isPending,任何加载状态都使用 isLoading
✅ 需要在继续之前确保数据为最新时,在 onSettled 中等待 invalidateQueries()
✅ 对分页查询使用 placeholderData,以避免界面闪烁
✅ 在乐观更新前使用 getQueryData 快照缓存
✅ 从 onMutate 返回上下文,以便在 onError 中回滚
✅ 在插件级别配置 staleTime 和 gcTime,作为整个应用的默认值
✅ 使用可复用的组合式函数封装查询,而不是内联使用 useQuery
切勿这样做
❌ 切勿使用普通字符串作为 key——始终使用数组
❌ 切勿从查询函数返回 undefined——应改为抛出错误
❌ 切勿直接修改 data.value——它是只读的
❌ 变更后切勿忘记使相关查询失效
❌ 切勿在查询中使用 onSuccess(不可用,应改用 watch)
❌ 切勿忘记等待 mutateAsync()——它会返回 Promise
❌ 乐观更新前切勿跳过 cancelQueries(这会导致竞态条件)
❌ 使用 getQueryData 时切勿不检查其是否为 undefined
❌ 切勿在 onMutate 中使查询失效(应在 onSettled 中执行)
❌ 切勿硬编码 URL——使用环境变量设置 API 基础 URL
预防最常见的 5 个错误
此技能可预防 12 个已记录的错误。以下是最常见的 5 个:
错误 #1:变更后查询未重新获取数据
错误:变更成功后,界面中的数据没有更新
预防方法:始终在 onSettled 中使用 invalidateQueries:
useMutation({
mutation: createTodo,
async onSettled() {
await queryCache.invalidateQueries({ key: ['todos'] })
},
})
参见:references/error-catalog.md #1
错误 #2:乐观更新中的竞态条件
错误:乐观更新被正在进行的请求覆盖
预防方法:始终在 onMutate 中调用 cancelQueries:
onMutate(id) {
cache.cancelQueries({ key: ['todos'] })
// Then do optimistic update
}
参见:references/error-catalog.md #2
错误 #3:SSR 水合不匹配
错误:Hydration completed but contains mismatches
预防方法:为 SSR 查询设置 refetchOnMount: false
useQuery({
key: ['todos'],
query: fetchTodos,
refetchOnMount: false, // Prevents SSR hydration mismatch
})
参见:references/error-catalog.md #3
错误 #4:查询键不具备响应性
错误:变量变化时查询不会重新获取数据 预防方法:使用函数创建响应式键:
// ❌ Wrong - static key
key: ['todos', id.value]
// ✅ Correct - reactive key
key: () => ['todos', id.value]
参见:references/error-catalog.md #4
错误 #5:Nuxt 模块顺序错误
错误:PiniaColada plugin not found 或 SSR 错误
预防:始终将 @pinia/nuxt 放在最前面:
export default defineNuxtConfig({
modules: [
'@pinia/nuxt', // MUST be first
'@pinia/colada-nuxt', // Then Colada
],
})
参见:references/error-catalog.md #10
完整错误目录(全部 12 个错误):参见 references/error-catalog.md
使用捆绑资源
参考文档(references/)
按需加载的详细指南:
-
references/setup-guide.md- 完整的 8 步设置流程- 安装并配置插件
- 创建可复用的查询组合式函数
- 了解查询键
- 实现变更
- 乐观更新
- 查询失效策略
- 分页查询
- SSR 和 Nuxt 集成
- 加载时机:用户需要详细的设置说明或高级模式时
-
references/common-patterns.md- 12 种常见模式- 依赖查询
- 并行查询
- 条件查询
- 后台同步模式
- 悬停时预取
- 使多个查询失效的变更
- 无限查询
- 乐观删除
- 带重试逻辑的查询
- 轮询查询
- 查询缓存预填充
- 手动触发查询
- 加载时机:用户询问“如何……”或需要特定模式时
-
references/error-catalog.md- 全部 12 个已记录的错误- 完整的错误消息和解决方案
- 预防策略
- 引用官方来源
- 预防检查清单
- 加载时机:用户遇到错误或希望预防问题时
-
references/configuration.md- 完整的配置参考- 插件选项(Vue 和 Nuxt)
- 单个查询选项
- 变更选项
- 查询缓存方法
- 高级模式(环境特定配置、错误处理、开发工具)
- TypeScript 配置
- 性能优化
- 加载时机:用户需要配置详情或高级设置时
-
references/migration-from-tanstack-vue-query.md- 迁移指南- API 差异
- Codemod 建议
- 破坏性变更
- 加载时机:用户提到 TanStack Vue Query 或迁移时
常见用例
- 基本待办事项列表,含 CRUD - 查询 + 通过失效处理的变更(10 分钟)→ 参见
references/setup-guide.md第 2–4 步 - 分页数据表 - 使用 placeholderData 的响应式键(15 分钟)→ 参见
references/setup-guide.md第 7 步 - 乐观 UI 更新 - 使用 onMutate/onError 回滚的变更(20 分钟)→ 参见
references/setup-guide.md第 5 步 - Nuxt SSR 应用 - 配合 refetchOnMount 配置使用自动导入(15 分钟)→ 参见
references/setup-guide.md第 8 步 - 实时仪表板 - 使用 refetchInterval 进行后台轮询(10 分钟)→ 参见
references/common-patterns.md模式 4
全部 5 个用例的完整代码示例,请参见 references/setup-guide.md 和 references/common-patterns.md。
何时加载详细参考文档
在以下情况下加载 references/setup-guide.md:
- 用户需要完整的 8 步设置流程
- 用户询问查询键或响应式键
- 用户需要了解如何实现乐观更新
- 用户询问 SSR/Nuxt 设置
- 用户需要实现分页
在以下情况下加载 references/common-patterns.md:
- 用户询问“如何……”并接着提出特定模式
- 用户需要依赖查询
- 用户询问预取
- 用户需要无限滚动
- 用户询问轮询或后台同步
在以下情况下加载 references/error-catalog.md:
- 用户遇到任何错误
- 用户询问故障排查
- 用户希望预防已知问题
- 用户询问“有哪些错误需要留意?”
- 用户遇到 SSR 水合问题
在以下情况下加载 references/configuration.md:
- 用户需要完整的配置选项
- 用户询问插件配置
- 用户需要 TypeScript 类型
- 用户希望优化性能
- 用户需要自定义插件
在以下情况下加载 references/migration-from-tanstack-vue-query.md:
- 用户提到 TanStack Vue Query
- 用户询问迁移
- 用户比较 Pinia Colada 与 TanStack Query
- 用户询问“与……有什么不同”
依赖项
必需:
- @pinia/[email protected] - 核心数据获取层
- [email protected]+ 或 [email protected]+ - 状态管理(对等依赖)
- [email protected]+ - 框架(对等依赖)
可选:
- @pinia/[email protected] - Nuxt 模块(需要单独安装 @pinia/nuxt)
官方文档
- Pinia Colada: https://pinia-colada.esm.dev/
- GitHub 仓库: https://github.com/posva/pinia-colada
- Pinia: https://pinia.vuejs.org/
- Nuxt 模块: https://nuxt.com/modules/pinia-colada
- 迁移指南: https://pinia-colada.esm.dev/cookbook/migration-tvq.html
软件包版本(已于 2025-11-28 验证)
{
"dependencies": {
"@pinia/colada": "^0.17.9",
"pinia": "^3.0.4",
"vue": "^3.5.25"
},
"devDependencies": {
"@pinia/colada-nuxt": "^0.17.9"
}
}
版本说明:
- Pinia Colada 0.17.9 是最新稳定版本(于 2025-11-21 发布)
- 兼容 Pinia 2.2.6+ 和 3.0+
- 需要 Vue 3.5.17+ 以获得最佳响应性
- Nuxt 模块版本与核心软件包一致
生产环境示例
此技能基于多个 Vue 3 和 Nuxt 应用中的生产环境实践:
- 节省 Token:相比手动配置 TanStack Query,约节省 65%
- 避免的错误:上文记录了 12 个常见问题
- 构建时间:基础配置少于 2 分钟
- 验证结果:✅ SSR 正常运行,✅ TypeScript 类型正确,✅ Nuxt 中自动导入正常
完整配置检查清单
使用此清单验证你的配置:
- 已安装
@pinia/colada和pinia(Nuxt 项目则安装@pinia/colada-nuxt) - 已在
createPinia()之后注册PiniaColada插件(Vue),或已将其添加到 modules(Nuxt) - 已使用
useQuery创建至少一个查询 - 已使用
useMutation创建至少一个变更 - 已在变更的
onSettled钩子中使用invalidateQueries - 查询键是数组(或返回数组的函数)
- 所有查询变量都包含在查询键中
- 查询/变更函数中抛出了错误(而不是返回错误)
- 初始加载状态使用
isPending - 已为所有数据结构定义 TypeScript 类型
- 已在插件级别配置
staleTime和gcTime(可选) - 开发环境运行时没有错误
- 使用 Nuxt 时 SSR 正常运行(检查 hydration)
有疑问?遇到问题? 请查看:官方文档 | references/setup-guide.md(8 步流程)| references/error-catalog.md(全部 12 个错误)| references/migration-from-tanstack-vue-query.md(迁移)| GitHub
此技能提供可直接用于生产环境的 Pinia Colada 配置,且不会出现配置错误。所有 12 个常见问题均有记录并已预防。