defineStore 详细介绍

📋 基本定义

defineStorePinia 库创建 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 三部分,提供了完整的状态管理解决方案。