定义 Store #
defineStore 函数 #
Store 是使用 defineStore 函数定义的。它接受两个参数:
- 唯一标识符:Store 的唯一 ID,用于 DevTools 和代码分割
- Store 定义:可以是 Options 对象或 Setup 函数
ts
import { defineStore } from 'pinia'
// Options Store
export const useCounterStore = defineStore('counter', {
state: () => ({ count: 0 }),
getters: { /* ... */ },
actions: { /* ... */ }
})
// Setup Store
export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
return { count }
})
Options Store #
Options Store 类似于 Vue 的 Options API,包含三个选项:
基本结构 #
ts
export const useUserStore = defineStore('user', {
// state: 返回初始状态的函数
state: () => ({
name: '',
email: '',
age: 0
}),
// getters: 计算属性
getters: {
isAdult: (state) => state.age >= 18,
displayName: (state) => state.name || 'Guest'
},
// actions: 方法(同步/异步)
actions: {
updateProfile(data) {
this.name = data.name
this.email = data.email
this.age = data.age
},
async fetchProfile() {
const response = await api.getProfile()
this.updateProfile(response.data)
}
}
})
完整示例 #
ts
// stores/todo.ts
import { defineStore } from 'pinia'
interface Todo {
id: number
text: string
completed: boolean
}
export const useTodoStore = defineStore('todo', {
state: () => ({
todos: [] as Todo[],
filter: 'all' as 'all' | 'active' | 'completed',
loading: false
}),
getters: {
filteredTodos: (state) => {
switch (state.filter) {
case 'active':
return state.todos.filter(todo => !todo.completed)
case 'completed':
return state.todos.filter(todo => todo.completed)
default:
return state.todos
}
},
remainingCount: (state) => {
return state.todos.filter(todo => !todo.completed).length
},
completedCount: (state) => {
return state.todos.filter(todo => todo.completed).length
}
},
actions: {
addTodo(text: string) {
this.todos.push({
id: Date.now(),
text,
completed: false
})
},
removeTodo(id: number) {
const index = this.todos.findIndex(todo => todo.id === id)
if (index !== -1) {
this.todos.splice(index, 1)
}
},
toggleTodo(id: number) {
const todo = this.todos.find(todo => todo.id === id)
if (todo) {
todo.completed = !todo.completed
}
},
setFilter(filter: 'all' | 'active' | 'completed') {
this.filter = filter
},
clearCompleted() {
this.todos = this.todos.filter(todo => !todo.completed)
},
async fetchTodos() {
this.loading = true
try {
const response = await fetch('/api/todos')
this.todos = await response.json()
} finally {
this.loading = false
}
}
}
})
Setup Store #
Setup Store 类似于 Vue 的 Composition API,使用函数定义:
基本结构 #
ts
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
export const useCounterStore = defineStore('counter', () => {
// state: 使用 ref 或 reactive
const count = ref(0)
// getters: 使用 computed
const doubleCount = computed(() => count.value * 2)
// actions: 普通函数
function increment() {
count.value++
}
function decrement() {
count.value--
}
// 必须返回所有需要暴露的属性
return {
count,
doubleCount,
increment,
decrement
}
})
完整示例 #
ts
// stores/todo.ts
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
interface Todo {
id: number
text: string
completed: boolean
}
export const useTodoStore = defineStore('todo', () => {
// State
const todos = ref<Todo[]>([])
const filter = ref<'all' | 'active' | 'completed'>('all')
const loading = ref(false)
// Getters
const filteredTodos = computed(() => {
switch (filter.value) {
case 'active':
return todos.value.filter(todo => !todo.completed)
case 'completed':
return todos.value.filter(todo => todo.completed)
default:
return todos.value
}
})
const remainingCount = computed(() => {
return todos.value.filter(todo => !todo.completed).length
})
const completedCount = computed(() => {
return todos.value.filter(todo => todo.completed).length
})
// Actions
function addTodo(text: string) {
todos.value.push({
id: Date.now(),
text,
completed: false
})
}
function removeTodo(id: number) {
const index = todos.value.findIndex(todo => todo.id === id)
if (index !== -1) {
todos.value.splice(index, 1)
}
}
function toggleTodo(id: number) {
const todo = todos.value.find(todo => todo.id === id)
if (todo) {
todo.completed = !todo.completed
}
}
function setFilter(newFilter: 'all' | 'active' | 'completed') {
filter.value = newFilter
}
function clearCompleted() {
todos.value = todos.value.filter(todo => !todo.completed)
}
async function fetchTodos() {
loading.value = true
try {
const response = await fetch('/api/todos')
todos.value = await response.json()
} finally {
loading.value = false
}
}
return {
// State
todos,
filter,
loading,
// Getters
filteredTodos,
remainingCount,
completedCount,
// Actions
addTodo,
removeTodo,
toggleTodo,
setFilter,
clearCompleted,
fetchTodos
}
})
两种风格对比 #
| 特性 | Options Store | Setup Store |
|---|---|---|
| 结构 | 类似 Options API | 类似 Composition API |
| 灵活性 | 固定结构 | 更灵活 |
| 组合性 | 有限 | 可以使用组合式函数 |
| 私有属性 | 不支持 | 支持(不返回即可) |
| 学习曲线 | 较低 | 需要了解 Composition API |
| TypeScript | 需要类型注解 | 自动推断 |
Options Store 适用场景 #
- 刚接触 Vue 的开发者
- 简单的状态管理需求
- 喜欢固定结构的团队
Setup Store 适用场景 #
- 熟悉 Composition API
- 需要更灵活的代码组织
- 需要使用组合式函数
- 需要私有属性或方法
使用组合式函数 #
Setup Store 的一个强大特性是可以使用组合式函数:
ts
// composables/useAsync.ts
import { ref } from 'vue'
export function useAsync<T>(asyncFn: () => Promise<T>) {
const data = ref<T | null>(null)
const loading = ref(false)
const error = ref<Error | null>(null)
async function execute() {
loading.value = true
error.value = null
try {
data.value = await asyncFn()
} catch (e) {
error.value = e
} finally {
loading.value = false
}
}
return { data, loading, error, execute }
}
ts
// stores/user.ts
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import { useAsync } from '@/composables/useAsync'
export const useUserStore = defineStore('user', () => {
const user = ref<User | null>(null)
// 使用组合式函数
const { loading, error, execute: fetchUser } = useAsync(async () => {
const response = await fetch('/api/user')
user.value = await response.json()
return user.value
})
const isLoggedIn = computed(() => !!user.value)
function logout() {
user.value = null
}
return {
user,
loading,
error,
isLoggedIn,
fetchUser,
logout
}
})
私有属性和方法 #
Setup Store 可以定义私有属性(不返回):
ts
export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
// 私有变量
const maxCount = 100
// 私有方法
function validate(value: number) {
return value >= 0 && value <= maxCount
}
// 公共方法
function increment() {
if (validate(count.value + 1)) {
count.value++
}
}
// 只返回公共属性
return {
count,
increment
}
})
Store 命名约定 #
推荐使用 use 前缀命名 Store:
ts
// 推荐
export const useUserStore = defineStore('user', { /* ... */ })
export const useCartStore = defineStore('cart', { /* ... */ })
export const useProductStore = defineStore('product', { /* ... */ })
// 不推荐
export const userStore = defineStore('user', { /* ... */ })
export const UserStore = defineStore('user', { /* ... */ })
下一步 #
现在你已经学会了如何定义 Store,接下来让我们深入了解 State 的使用。
- State状态 - 状态的定义和修改
最后更新:2026-03-28