Pinia状态管理有哪些常用API?

Pinia 是 Vue.js 的官方状态管理库,它取代了 Vuex,提供了更简洁、直观且类型友好的 API。以下是 Pinia 中最常用的核心 API 及其用法:


1. defineStore() - 定义 Store

这是创建一个 store 的核心 API。它接受一个唯一的 ID 和一个配置对象(或 setup 函数)。

javascript 复制代码
javascript
深色版本
// stores/counter.js
import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', {
  // 状态 (State)
  state: () => ({
    count: 0,
    name: 'Eduardo'
  }),

  // 计算属性 (Getters)
  getters: {
    doubleCount: (state) => state.count * 2,
    // 带参数的 getter
    getByName: (state) => {
      return (name) => state.name === name
    }
  },

  // 动作 (Actions)
  actions: {
    increment() {
      this.count++
    },
    decrement() {
      this.count--
    },
    // 异步操作
    async fetchUser() {
      const res = await fetch('/api/user')
      this.name = await res.json()
    }
  }
})

说明defineStore 返回一个函数(如 useCounterStore),调用它即可获取 store 实例。


2. state - 状态

用于定义 store 中的响应式数据。

  • 必须是一个函数,返回一个包含状态的对象。
  • 可以在组件中直接读取和修改。
yaml 复制代码
javascript
深色版本
state: () => ({
  count: 0,
  todos: []
})

3. getters - 计算属性

类似于 Vue 组件中的 computed,用于派生状态。

  • 接收 state 作为第一个参数。
  • 支持缓存,只有依赖的 state 变化时才会重新计算。
  • 可以接受参数(返回一个函数)。
javascript 复制代码
javascript
深色版本
getters: {
  // 基础 getter
  doubleCount: (state) => state.count * 2,

  // 带参数的 getter
  getTodoById: (state) => {
    return (id) => state.todos.find(todo => todo.id === id)
  }
}

4. actions - 动作

用于定义修改 state 的方法,支持同步和异步操作。

  • 可以通过 this 访问 stategetters 和其他 actions
  • 是修改 state 的唯一推荐方式(虽然可以直接修改,但不推荐)。
javascript 复制代码
javascript
深色版本
actions: {
  increment() {
    this.count++
  },
  async fetchData() {
    const data = await api.getData()
    this.todos = data
  }
}

5. 在组件中使用 Store

在组件中通过调用 useXxxStore() 函数来使用 store。

xml 复制代码
vue
深色版本
<script setup>
import { useCounterStore } from '@/stores/counter'

const counter = useCounterStore()

// 直接访问 state, getters, actions
console.log(counter.count)         // state
console.log(counter.doubleCount)   // getter
counter.increment()                // action
</script>

<template>
  <div>
    <p>Count: {{ counter.count }}</p>
    <p>Double: {{ counter.doubleCount }}</p>
    <button @click="counter.increment">+</button>
  </div>
</template>

注意 :从 store 中解构变量会失去响应性 。如果需要解构,应使用 storeToRefs()


6. storeToRefs() - 保持解构后的响应性

当你想从 store 中解构 state 或 getters 并保持响应性时,使用此工具函数。

xml 复制代码
vue
深色版本
<script setup>
import { storeToRefs } from 'pinia'
import { useCounterStore } from '@/stores/counter'

const counter = useCounterStore()
// ❌ 错误:count 失去响应性
// const { count, doubleCount } = counter

// ✅ 正确:使用 storeToRefs
const { count, doubleCount } = storeToRefs(counter)
const { increment } = counter // actions 不需要,因为不是响应式引用
</script>

7. mapState, mapGetters, mapActions - 映射辅助函数

在选项式 API(Options API)中,可以使用这些辅助函数将 store 的内容映射到组件中。

javascript 复制代码
javascript
深色版本
import { mapState, mapActions } from 'pinia'
import { useCounterStore } from '@/stores/counter'

export default {
  computed: {
    // 映射 state
    ...mapState(useCounterStore, ['count', 'name']),
    // 或者重命名
    ...mapState(useCounterStore, {
      myCount: 'count'
    })
  },
  methods: {
    // 映射 actions
    ...mapActions(useCounterStore, ['increment', 'fetchUser'])
  }
}

8. $reset() - 重置状态

每个 store 实例都暴露一个 $reset() 方法,用于将 state 重置为初始值。

scss 复制代码
javascript
深色版本
const counter = useCounterStore()
counter.$reset() // 将 count 重置为 0

9. $subscribe() - 订阅状态变化

监听 store 的 state 变化,类似于 Vuex 的 subscribe。

javascript 复制代码
javascript
深色版本
const counter = useCounterStore()

// 订阅 state 变化
const unsubscribe = counter.$subscribe((mutation, state) => {
  // mutation: 包含 type 等信息
  // state: 最新的 state
  console.log('State changed:', state.count)
})

// 取消订阅
// unsubscribe()

总结

API 用途
defineStore() 定义一个 store
state 定义响应式数据
getters 定义计算属性
actions 定义修改 state 的方法(支持异步)
useXxxStore() 在组件中使用 store
storeToRefs() 解构 store 时保持响应性
mapState / mapGetters / mapActions 选项式 API 中的映射辅助函数
$reset() 重置 state 到初始值
$subscribe() 监听 state 变化
相关推荐
雪芽蓝域zzs21 分钟前
(六)打包优化 + Nginx 部署完整配置 + 项目收尾
前端·vue.js
研☆香29 分钟前
聊一聊前端的常见字 关键字
开发语言·前端·javascript
东风破_1 小时前
JWT 1:从一个登录请求开始,理解 React 项目里的 API 层与 Mock
前端·后端
东风破_1 小时前
JWT 3:为什么 Token 要放进 Authorization?Axios 拦截器到底解决了什么?
前端·后端
东风破_1 小时前
JWT 5:路由守卫是什么?把整个 JWT 登录鉴权流程串起来
前端·后端
东风破_1 小时前
JWT 2:HTTP 是无状态的,为什么登录成功后还要给 Token?
前端·后端
东风破_1 小时前
JWT 4:Zustand 到底解决了什么?为什么登录状态要放进 Store?
前端·后端
IT_陈寒1 小时前
Vite动态导入差点让我秃头,原来问题出在这
前端·人工智能·后端
白泽_hunter2 小时前
项目里最常见的 5 个 this 指向坑:从规则到实战彻底讲透
前端
宿6742 小时前
vue3-pinia
前端·vue.js