defineStore 详细介绍
📋 基本定义
defineStore 是 Pinia 库创建 Store 的核心函数,用于定义和管理应用状态。
🔧 方法签名
defineStore(id, options | setup)
📊 两种调用方式
方式1:Options API(常用)
const useStore = defineStore(id, {
// 必需:状态数据
state: () => ({ /* 初始状态 */ }),
// 可选:计算属性
getters: { /* getter 函数 */ },
// 可选:操作方法
actions: { /* action 函数 */ }
})
方式2:Setup API
const useStore = defineStore(id, () => {
// 使用组合式 API
const state = ref()
const getter = computed(() => {})
const action = () => {}
return { state, getter, action }
})
🎯 参数详解 ★
1. id(必需)- 字符串
defineStore('user', { /* ... */ })
- 作用:Store 的唯一标识符
- 要求:必须全局唯一
- 示例:
'user'、'cart'、'settings'
2. state(必需)- 函数
state: () => ({
count: 0,
name: '',
list: []
})
- 作用:定义初始状态
- 必须返回对象
- 响应式:自动转为响应式数据
3. getters(可选)- 对象
getters: {
// 方式1:普通函数
doubleCount(state) {
return state.count * 2
},
// 方式2:箭头函数
tripleCount: (state) => state.count * 3,
// 访问其他 getter
complexGetter(state) {
return this.doubleCount + 10
}
}
- 作用:计算属性/派生状态
- 参数:可接收
state作为第一个参数 - 缓存:计算结果会被缓存
4. actions(可选)- 对象
actions: {
// 同步 action
increment() {
this.count++ // 通过 this 访问 state
},
// 异步 action
async fetchData() {
const data = await api.getData()
this.list = data
}
}
- 作用:业务逻辑/操作方法
- 可修改 state:通过
this访问和修改状态 - 支持异步:可以是 async 函数
💡 完整示例
用户管理 Store
import { defineStore } from 'pinia'
export const useUserStore = defineStore('user', {
// 1. 状态
state: () => ({
id: null,
name: '',
token: '',
isLoggedIn: false
}),
// 2. 计算属性
getters: {
// 用户名首字母大写
formattedName: (state) => {
return state.name.charAt(0).toUpperCase() + state.name.slice(1)
},
// 是否管理员
isAdmin: (state) => {
return state.id === 1
}
},
// 3. 操作方法
actions: {
// 登录
async login(credentials) {
const response = await api.login(credentials)
this.id = response.data.id
this.name = response.data.name
this.token = response.data.token
this.isLoggedIn = true
// 保存到本地存储
localStorage.setItem('token', this.token)
},
// 退出登录
logout() {
this.$reset() // 重置状态
localStorage.removeItem('token')
},
// 更新用户信息
updateProfile(data) {
this.name = data.name
// 可以调用其他 action
this.syncToBackend()
},
// 私有方法(不需要导出)
syncToBackend() {
// 同步到后端
}
}
})
🎯 在组件中使用
导入和使用
<script setup>
import { useUserStore } from '@/stores/user'
// 1. 获取 store 实例
const userStore = useUserStore()
// 2. 访问 state
console.log(userStore.name)
console.log(userStore.isLoggedIn)
// 3. 使用 getter
console.log(userStore.formattedName)
console.log(userStore.isAdmin)
// 4. 调用 action
const handleLogin = async () => {
await userStore.login({
username: 'admin',
password: '123456'
})
}
const handleLogout = () => {
userStore.logout()
}
</script>
<template>
<!-- 在模板中直接使用 -->
<div v-if="userStore.isLoggedIn">
欢迎,{{ userStore.formattedName }}
</div>
</template>
🔧 常用 API
1. 访问 state
// 直接访问
userStore.name
// 响应式解构(保持响应性)
import { storeToRefs } from 'pinia'
const { name, isLoggedIn } = storeToRefs(userStore)
2. 修改 state
// 方式1:直接修改
userStore.name = '新名字'
// 方式2:使用 $patch(批量修改)
userStore.$patch({
name: '新名字',
isLoggedIn: true
})
// 方式3:使用 $patch 函数
userStore.$patch((state) => {
state.name = '新名字'
state.list.push(newItem)
})
// 方式4:调用 action
userStore.updateProfile({ name: '新名字' })
3. 重置状态
// 重置为初始状态
userStore.$reset()
4. 订阅变化
// 监听 state 变化
userStore.$subscribe((mutation, state) => {
console.log('状态变化:', mutation.type)
console.log('新状态:', state)
})
// 监听 action
userStore.$onAction(({ name, store, args, after, onError }) => {
console.log(`执行 action: ${name}`)
after((result) => {
console.log('action 执行完成')
})
onError((error) => {
console.error('action 执行失败:', error)
})
})
📈 TypeScript 支持
完整类型定义
interface User {
id: number
name: string
email: string
}
interface UserState {
user: User | null
token: string | null
permissions: string[]
}
export const useUserStore = defineStore('user', {
// 明确 state 类型
state: (): UserState => ({
user: null,
token: null,
permissions: []
}),
getters: {
// getter 类型推断
hasPermission: (state) => (permission: string) => {
return state.permissions.includes(permission)
}
},
actions: {
// action 参数类型
setUser(user: User) {
this.user = user
},
async fetchUser(id: number): Promise<User> {
const response = await api.getUser(id)
this.user = response.data
return response.data
}
}
})
⚡ 最佳实践
1. 命名规范
// store 文件:stores/user.ts
// store id:'user'
// 导出名:useUserStore
// 使用:const userStore = useUserStore()
2. 模块化组织
stores/
├── user.ts # 用户相关
├── cart.ts # 购物车
├── product.ts # 商品
├── order.ts # 订单
└── index.ts # 统一导出
3. 组合 Store
// 组合多个 store
export function useDashboard() {
const userStore = useUserStore()
const orderStore = useOrderStore()
const productStore = useProductStore()
const dashboardData = computed(() => ({
user: userStore.name,
orderCount: orderStore.orders.length,
productCount: productStore.products.length
}))
return { dashboardData }
}
📊 总结要点
| 部分 | 作用 | 是否必需 | 特点 |
|---|---|---|---|
| id | 唯一标识 | ✅ 必需 | 字符串,全局唯一 |
| state | 状态数据 | ✅ 必需 | 函数,返回初始状态 |
| getters | 计算属性 | ❌ 可选 | 可缓存,可组合 |
| actions | 操作方法 | ❌ 可选 | 支持异步,可修改 state |
💡 一句话总结
defineStore 用于定义 Pinia Store,包含 state、getters、actions 三部分,提供了完整的状态管理解决方案。
