《Pinia 从入门到精通》Vue 3 官方状态管理 – 基础入门篇
《Pinia 从入门到精通》Vue 3 官方状态管理 – 进阶使用篇
《Pinia 从入门到精通》Vue 3 官方状态管理 – 插件扩展篇
📖 教程目录
- 为什么选择 Pinia?
- 1.1 背景介绍
- 1.2 Vuex 的痛点(对比说明)
- 1.3 Pinia 的优势
- 1.4 使用场景
- 安装与快速上手
- 2.1 安装 Pinia
- 2.2 在项目中注册 Pinia
- 2.3 创建第一个 Store
- 2.4 在组件中使用 Store
- 2.5 使用 DevTools 调试
- 2.6 快速回顾
- ✅ 小结
- 核心概念解析 —— State、Getter、Action 深入理解
- 3.1 State —— 响应式数据源
- ✅ 定义方式
- ✅ 特点
- 📌 使用建议
- 3.2 Getter —— 派生计算属性
- ✅ 定义方式
- ✅ 特点
- 📌 使用建议
- 3.3 Action —— 方法逻辑封装
- ✅ 定义方式
- ✅ 特点
- 📌 使用建议
- 3.4 示例整合
- ✅ 小结
为什么选择 Pinia?
1.1 背景介绍
Vuex 是 Vue 2 时代的官方状态管理库,但到了 Vue 3,Pinia 成为了 Vue 官方推荐的新一代状态管理解决方案。Pinia 的设计理念更贴近 Vue 3 的 Composition API,同时解决了 Vuex 中的一些设计痛点。
1.2 Vuex 的痛点(对比说明)
问题 | Vuex 表现 | Pinia 改进 |
---|---|---|
API 复杂 | 四个概念:state, mutation, action, getter | 仅需 state, getter, action,简洁直观 |
类型支持差 | TypeScript 体验差,类型推导复杂 | TS 完善支持,store 类型自动推导 |
严格模式限制 | mutation 强制同步,异步处理不直观 | action 中自由处理异步逻辑 |
模块嵌套繁琐 | 多模块配置臃肿、调试困难 | 每个 store 独立定义、组合灵活 |
1.3 Pinia 的优势
- 📦 极简 API:你甚至可以用纯 JavaScript 写出 Vuex 的一半代码量
- ⚙️ 完美支持 TypeScript:无须手动类型推导
- 🚀 原生支持 Devtools,调试体验极佳
- 🧩 插件机制灵活,生态成熟
- 🌱 无需注册、按需使用,天然模块化设计
1.4 使用场景
Pinia 适用于所有 Vue 3 项目,尤其推荐在以下场景中使用:
- 中大型项目,状态多、模块复杂
- 需要 SSR 或 Nuxt 支持
- 强类型开发团队,希望完善 TS 体验
- 希望未来迁移方便,避免被 Vuex 设计束缚
好的,接下来我们将从安装 Pinia 开始,快速构建第一个 Store,并在 Vue 组件中使用它。
安装与快速上手
将带你完成以下目标:
- 安装并配置 Pinia
- 创建第一个 Store
- 在组件中使用 State、Getter、Action
- 初识 DevTools 与响应式调试
2.1 安装 Pinia
在 Vue 3 项目中安装 Pinia 非常简单:
npm install pinia
# 或
yarn add pinia
# 或
pnpm add pinia
2.2 在项目中注册 Pinia
以 Vite + Vue 3 项目为例,在 main.ts
或 main.js
中注册 Pinia:
// main.ts
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
const app = createApp(App)
app.use(createPinia()) // 注册 Pinia
app.mount('#app')
2.3 创建第一个 Store
Pinia 中的 Store 是一个函数,通常我们放在 stores
文件夹下,每个 Store 文件代表一个独立模块。
// stores/counter.ts
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', {
state: () => ({
count: 0,
name: 'Pinia Demo'
}),
getters: {
doubleCount: (state) => state.count * 2
},
actions: {
increment() {
this.count++
},
async fetchCountFromServer() {
const result = await fetch('/api/count').then(res => res.json())
this.count = result.count
}
}
})
2.4 在组件中使用 Store
我们在组件中使用 Store 的方式如下,注意 useCounterStore()
是一个函数,必须在 setup()
中调用:
<script setup lang="ts">
import { useCounterStore } from '@/stores/counter'
const counter = useCounterStore()
function handleClick() {
counter.increment()
}
</script>
<template>
<div>
<p>当前计数:{{ counter.count }}</p>
<p>计数翻倍:{{ counter.doubleCount }}</p>
<button @click="handleClick">+1</button>
</div>
</template>
2.5 使用 DevTools 调试
Pinia 默认集成了 Vue DevTools。打开浏览器的开发者工具,切换到 “Pinia” 标签页:
- 可实时查看 Store 中的
state
- 支持时间旅行(Time-travel Debugging)
- 可跟踪每一次
action
的调用和参数
2.6 快速回顾
名称 | 说明 |
---|---|
state | 存储响应式状态 |
getter | 计算属性,依赖 state,具缓存能力 |
action | 可执行逻辑(同步/异步),可以修改 state |
defineStore | 定义一个 Store 函数 |
useXXXStore | 在组件中访问 Store,命名建议以 use 开头 |
✅ 小结
通过本章,你已经完成了从安装、配置、到创建并使用第一个 Pinia Store 的全过程。你应该已经能够在项目中灵活使用 state、getter 与 action,并通过 DevTools 进行调试。
好的,以下是第三章:核心概念解析的完整内容。我们将深入理解 Pinia 的核心组成部分,并结合实用示例与图示进行讲解,为后续进阶打下坚实基础。
核心概念解析 —— State、Getter、Action 深入理解
Pinia 是围绕三个核心概念构建的:State、Getter 和 Action,这三者构成了所有 Store 的基石。
3.1 State —— 响应式数据源
✅ 定义方式
在 defineStore
中通过 state: () => ({})
返回一个对象,即为该 Store 的状态树。
state: () => ({
count: 0,
userInfo: { name: 'Alice', age: 25 }
})
✅ 特点
- 是响应式的(由
reactive
封装) - 可直接在组件中解构使用
- 会被持久化插件等作为数据源操作
📌 使用建议
- 状态初始值应明确,不使用
undefined
- 尽量避免嵌套过深(会增加调试成本)
3.2 Getter —— 派生计算属性
✅ 定义方式
类似 Vue 的 computed 属性,依赖 State 自动更新,具备缓存能力。
getters: {
doubleCount: (state) => state.count * 2,
userSummary: (state) => `${state.userInfo.name} (${state.userInfo.age})`
}
✅ 特点
- Getter 本质是
computed
- 可以使用
this
访问其他 getter 和 state
getters: {
doubleCount: (state) => state.count * 2,
tripleCount() {
return this.doubleCount + this.count
}
}
📌 使用建议
- 用于展示层逻辑,避免副作用(不要在 getter 中修改 state)
- 可以将复杂的 UI 显示逻辑移入 getter,保持组件简洁
3.3 Action —— 方法逻辑封装
✅ 定义方式
类似 Vue 的 methods,用于封装业务逻辑。支持异步、可直接修改 state。
actions: {
increment() {
this.count++
},
async loadUser() {
const data = await fetch('/api/user').then(res => res.json())
this.userInfo = data
}
}
✅ 特点
- 可以包含异步逻辑(使用 async/await)
- 可组合调用其他 actions
- 可接收参数
actions: {
updateUserName(name: string) {
this.userInfo.name = name
}
}
📌 使用建议
- 所有数据修改逻辑应封装到 Action 中,保持一致性
- 异步请求、表单提交、事件处理等建议全部写在 Action 中
3.4 示例整合
// stores/user.ts
import { defineStore } from 'pinia'
export const useUserStore = defineStore('user', {
state: () => ({
name: 'Alice',
age: 25
}),
getters: {
summary: (state) => `${state.name}, 年龄 ${state.age}`
},
actions: {
setName(newName: string) {
this.name = newName
},
async fetchUser() {
const data = await fetch('/api/user').then(res => res.json())
this.name = data.name
this.age = data.age
}
}
})
组件中使用:
<script setup lang="ts">
import { useUserStore } from '@/stores/user'
const userStore = useUserStore()
function changeName() {
userStore.setName('Bob')
}
</script>
<template>
<div>
<p>{{ userStore.summary }}</p>
<button @click="changeName">修改名字</button>
</div>
</template>
✅ 小结
概念 | 本质 | 功能 | 类比 Vue 中 |
---|---|---|---|
State | reactive | 存储响应式数据 | data |
Getter | computed | 派生属性、自动缓存 | computed |
Action | 普通函数/方法 | 封装业务逻辑,支持异步、状态更新等 | methods |
理解这三者后,你就掌握了 Pinia 的全部运行机制。它不再区分 mutation 与 action,让状态管理更加直观、自由。