Pinia 极简指南:Vue 3 官方状态管理库

这是一篇精简、易懂的 Pinia 入门整理,适合快速了解核心用法。

一、Pinia 是什么?

Pinia 是 Vue 生态的新一代状态管理库,已取代 Vuex 成为 Vue 3 的官方推荐方案。 它让你能在组件之间共享数据(状态),同时保持响应式、类型安全和开发工具友好。

一句话:Pinia = 更轻量、更直觉的 Vuex。


二、为什么选 Pinia,而不是 Vuex?

特性 Pinia Vuex 4
语法简洁 没有 mutations,直接改状态 必须通过 commit 提交 mutation
TypeScript 支持 完美自动推断,无需额外类型声明 需要手动封装,体验较差
模块化 天然的多个 store,无需嵌套模块 需要 module 嵌套,命名空间复杂
体积 ~1 KB 较大
开发工具 Devtools 支持、热更新、时间旅行 支持,但不如 Pinia 顺畅

核心理念变化

Pinia 不再区分 mutationsactions --- 所有修改都直接通过 actions 或直接赋值完成,代码量明显减少。


三、核心概念

Pinia 的应用由多个独立的 Store 组成,每个 Store 就是一个独立的状态单元。

一个 Store 包含三部分:

  • State(状态) :存放数据的响应式对象,相当于组件的 data
  • Getters(计算属性) :基于 state 计算的派生值,相当于 computed
  • Actions(方法) :执行修改 state 的逻辑(同步或异步),相当于 methods

四、两种定义方式

选项式 Store(类似 Vue 2 写法)

javascript 复制代码
import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', {
  state: () => ({
    count: 0
  }),
  getters: {
    double: (state) => state.count * 2
  },
  actions: {
    increment() {
      this.count++
    }
  }
})

组合式 Store(推荐,更像 Vue 3 的 setup 函数)

javascript 复制代码
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', () => {
  const count = ref(0)
  const double = computed(() => count.value * 2)

  function increment() {
    count.value++
  }

  return { count, double, increment }
})

组合式写法让你可以复用逻辑,和写一个普通 composable 一样,学习成本极低。


五、在组件中使用

vue 复制代码
<script setup>
import { useCounterStore } from '@/stores/counter'

const counter = useCounterStore()

// 访问 state
console.log(counter.count)

// 读取 getter
console.log(counter.double)

// 调用 action
counter.increment()

// 直接修改 state(允许,但推荐在 action 中集中处理)
counter.count++
</script>

注意 :直接修改 state 在 Pinia 中是完全合法的,不会破坏响应式。但为了可维护性,通常建议将修改逻辑封装在 action 里。


六、Pinia 最佳实践

  1. 一个功能一个 Store

    不要把所有状态堆在一起,按业务或功能拆分成独立 store,如 useUserStoreuseCartStore

  2. 使用组合式 Store

    更灵活、更容易提取逻辑,也更符合 Vue 3 的组合式思维。

  3. 把异步请求放进 actions

    actions 支持 async/await,适合封装 API 调用并 update 状态。

  4. 利用 storeToRefs 保持解构响应性

    直接从 store 解构会失去响应式,需使用:

    javascript 复制代码
    import { storeToRefs } from 'pinia'
    const { count, double } = storeToRefs(counter)

    actions 可以直接解构,无需特殊处理。

  5. 注入全局 store 按需使用

    Pinia 无需在入口处挂载整个模块树,只需在 app.use(pinia) 创建实例后,随时在组件里调用 useXxxStore()


七、一个完整的小示例

stores/todo.js

javascript 复制代码
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'

export const useTodoStore = defineStore('todo', () => {
  const list = ref([])
  const filter = ref('all')

  const filteredList = computed(() => {
    if (filter.value === 'done') return list.value.filter(t => t.done)
    if (filter.value === 'todo') return list.value.filter(t => !t.done)
    return list.value
  })

  function addTodo(text) {
    list.value.push({ id: Date.now(), text, done: false })
  }

  function toggle(id) {
    const todo = list.value.find(t => t.id === id)
    if (todo) todo.done = !todo.done
  }

  return { list, filter, filteredList, addTodo, toggle }
})

组件中使用

vue 复制代码
<template>
  <input v-model="newTodo" @keyup.enter="add" />
  <ul>
    <li v-for="t in todoStore.filteredList" :key="t.id">
      <input type="checkbox" :checked="t.done" @change="todoStore.toggle(t.id)" />
      {{ t.text }}
    </li>
  </ul>
</template>

<script setup>
import { ref } from 'vue'
import { useTodoStore } from '@/stores/todo'

const todoStore = useTodoStore()
const newTodo = ref('')

function add() {
  if (newTodo.value.trim()) {
    todoStore.addTodo(newTodo.value)
    newTodo.value = ''
  }
}
</script>

八、总结

  • Pinia 是 Vue 官方指定的下一代状态管理库,更简洁、更灵活、TypeScript 更友好
  • 核心就是通过 defineStore 定义一个状态单元,组件中直接调用即可。
  • 推荐使用 组合式语法,将状态、计算属性和方法像写 composable 一样组织。
  • 没有 mutation,没有模块嵌套,只有你需要的功能

若你正从 Vuex 迁移,或者直接在 Vue 3 项目中使用状态管理,大胆选择 Pinia --- 它会让你少写很多代码,思路也更清晰。

相关推荐
sayamber1 小时前
vLLM 容器化部署实战:如何在云服务器上跑起高并发大模型推理服务
前端
燐妤2 小时前
前端HTML编程2:深入学习表单与表格
前端·学习·html5
朝阳392 小时前
react【实战】首页 -- 响应式导航栏(含带联动动画的搜索框)
前端·react.js·前端框架
贾铭2 小时前
如何实现一个网页版的剪映(五)如何跳转到视频某一帧
前端·后端
Ruihong2 小时前
手写 React 对比 VuReact 编译:真正省下来的是维护成本
vue.js·react.js·面试
林恒smileZAZ2 小时前
CSS 滚动驱动动画(scroll-timeline):无 JS 实现滚动特效
前端·javascript·css
俺不会敲代码啊啊啊2 小时前
el-table实现行拖拽(包含展开项)
前端·vue.js·typescript
LIO2 小时前
React Router 极简指南(v6+)
前端·react.js
明月_清风2 小时前
从 AST 视角看透前端工程化:一条编译管线如何串联起所有工具
前端