Loading...
Loading...
Compare original and translation side by side
bun add @pinia/colada pinia # preferredbun add @pinia/colada pinia # 推荐方式
**For Nuxt Projects:**
```bash
bun add @pinia/nuxt @pinia/colada-nuxt # install both Pinia and Pinia Colada modules
**Nuxt项目适用**:
```bash
bun add @pinia/nuxt @pinia/colada-nuxt # 同时安装Pinia和Pinia Colada模块
**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
**重要说明**:
- Pinia Colada 需要 Pinia 2.2.6+ 或 3.0+ 作为对等依赖项
- Nuxt模块会自动处理SSR序列化
- 推荐使用Vue 3.5.17+以获得最佳响应式体验// 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.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,
},
},
})@pinia/nuxt@pinia/colada-nuxt// 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, {
// 可选:配置默认参数
query: {
staleTime: 5000, // 5秒
gcTime: 5 * 60 * 1000, // 5分钟(垃圾回收)
refetchOnMount: true,
refetchOnWindowFocus: false,
},
})
app.mount('#app')// nuxt.config.ts
export default defineNuxtConfig({
modules: [
'@pinia/nuxt', // 必须在@pinia/colada-nuxt之前
'@pinia/colada-nuxt',
],
// 可选:配置Pinia Colada
piniaColada: {
query: {
staleTime: 5000,
gcTime: 5 * 60 * 1000,
},
},
})@pinia/nuxt@pinia/colada-nuxt<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>keyqueryisPendingtrueisLoading<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> - 初始加载状态
isLoading, // Ref<boolean> - 所有加载状态(包括重新获取)
error, // Ref<Error | null>
refresh, // () => Promise<void> - 手动重新获取
} = useQuery({
key: ['todos'],
query: fetchTodos,
})
</script>
<template>
<div>
<div v-if="isPending">加载待办事项中...</div>
<div v-else-if="error">错误:{{ error.message }}</div>
<ul v-else-if="data">
<li v-for="todo in data" :key="todo.id">
{{ todo.title }}
</li>
</ul>
</div>
</template>keyqueryisPendingtrueisLoading<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>onSettledinvalidateQueriesmutatemutateAsync<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,
// Mutation成功后失效待办事项查询
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 ? '添加中...' : '添加待办事项' }}
</button>
<div v-if="error">错误:{{ error.message }}</div>
</form>
</template>onSettledinvalidateQueriesmutatemutateAsyncuseQueryCache()isPendingisLoadinginvalidateQueries()onSettledplaceholderDatagetQueryDataonMutateonErrorstaleTimegcTimeuseQueryCache()isPendingisLoadingonSettledinvalidateQueries()placeholderDatagetQueryDataonMutateonErrorstaleTimegcTimedata.valueonSuccessmutateAsync()cancelQueriesgetQueryDataonMutateonSettleddata.valueonSuccessmutateAsync()cancelQueriesgetQueryDataonMutateonSettledinvalidateQueriesonSettleduseMutation({
mutation: createTodo,
async onSettled() {
await queryCache.invalidateQueries({ key: ['todos'] })
},
})references/error-catalog.mdonSettledinvalidateQueriesuseMutation({
mutation: createTodo,
async onSettled() {
await queryCache.invalidateQueries({ key: ['todos'] })
},
})references/error-catalog.mdcancelQueriesonMutateonMutate(id) {
cache.cancelQueries({ key: ['todos'] })
// Then do optimistic update
}references/error-catalog.mdonMutatecancelQueriesonMutate(id) {
cache.cancelQueries({ key: ['todos'] })
// 然后执行乐观更新
}references/error-catalog.mdHydration completed but contains mismatchesrefetchOnMount: falseuseQuery({
key: ['todos'],
query: fetchTodos,
refetchOnMount: false, // Prevents SSR hydration mismatch
})references/error-catalog.mdHydration completed but contains mismatchesrefetchOnMount: falseuseQuery({
key: ['todos'],
query: fetchTodos,
refetchOnMount: false, // 防止SSR hydration不匹配
})references/error-catalog.md// ❌ Wrong - static key
key: ['todos', id.value]
// ✅ Correct - reactive key
key: () => ['todos', id.value]references/error-catalog.md// ❌ 错误 - 静态key
key: ['todos', id.value]
// ✅ 正确 - 响应式key
key: () => ['todos', id.value]references/error-catalog.mdPiniaColada plugin not found@pinia/nuxtexport default defineNuxtConfig({
modules: [
'@pinia/nuxt', // MUST be first
'@pinia/colada-nuxt', // Then Colada
],
})references/error-catalog.mdreferences/error-catalog.mdPiniaColada plugin not found@pinia/nuxtexport default defineNuxtConfig({
modules: [
'@pinia/nuxt', // 必须放在前面
'@pinia/colada-nuxt', // 然后是Colada
],
})references/error-catalog.mdreferences/error-catalog.mdreferences/setup-guide.mdreferences/common-patterns.mdreferences/error-catalog.mdreferences/configuration.mdreferences/migration-from-tanstack-vue-query.mdreferences/setup-guide.mdreferences/common-patterns.mdreferences/error-catalog.mdreferences/configuration.mdreferences/migration-from-tanstack-vue-query.mdreferences/setup-guide.mdreferences/setup-guide.mdreferences/setup-guide.mdreferences/setup-guide.mdreferences/common-patterns.mdreferences/setup-guide.mdreferences/common-patterns.mdreferences/setup-guide.mdreferences/setup-guide.mdreferences/setup-guide.mdreferences/setup-guide.mdreferences/common-patterns.mdreferences/setup-guide.mdreferences/common-patterns.mdreferences/setup-guide.mdreferences/common-patterns.mdreferences/error-catalog.mdreferences/configuration.mdreferences/migration-from-tanstack-vue-query.mdreferences/setup-guide.mdreferences/common-patterns.mdreferences/error-catalog.mdreferences/configuration.mdreferences/migration-from-tanstack-vue-query.md{
"dependencies": {
"@pinia/colada": "^0.17.9",
"pinia": "^3.0.4",
"vue": "^3.5.25"
},
"devDependencies": {
"@pinia/colada-nuxt": "^0.17.9"
}
}{
"dependencies": {
"@pinia/colada": "^0.17.9",
"pinia": "^3.0.4",
"vue": "^3.5.25"
},
"devDependencies": {
"@pinia/colada-nuxt": "^0.17.9"
}
}@pinia/coladapinia@pinia/colada-nuxtPiniaColadacreatePinia()useQueryuseMutationinvalidateQueriesonSettledisPendingstaleTimegcTimereferences/setup-guide.mdreferences/error-catalog.mdreferences/migration-from-tanstack-vue-query.md@pinia/coladapinia@pinia/colada-nuxtcreatePinia()PiniaColadauseQueryuseMutationonSettledinvalidateQueriesisPendingstaleTimegcTimereferences/setup-guide.mdreferences/error-catalog.mdreferences/migration-from-tanstack-vue-query.md