文章目录
-
-
- [一、Pinia 核心介绍](#一、Pinia 核心介绍)
-
- [1. 核心优势](#1. 核心优势)
- [2. 核心概念](#2. 核心概念)
- [二、Vue 3 中配置 Pinia](#二、Vue 3 中配置 Pinia)
-
- [1. 安装](#1. 安装)
- [2. 全局注册(main.ts/main.js)](#2. 全局注册(main.ts/main.js))
- [三、Store 定义(两种风格)](#三、Store 定义(两种风格))
-
- [方式 1:选项式(Options API,兼容 Vue 2)](#方式 1:选项式(Options API,兼容 Vue 2))
- [方式 2:组合式(Composition API,Vue 3 推荐)](#方式 2:组合式(Composition API,Vue 3 推荐))
- [四、组件中使用(<script setup>)](#四、组件中使用(<script setup>))
-
- [1. 基础使用](#1. 基础使用)
- [2. 多 Store / 异步示例](#2. 多 Store / 异步示例)
- 五、高级特性
-
- [1. 状态持久化(刷新不丢失)](#1. 状态持久化(刷新不丢失))
- [2. reset / subscribe / onAction](#2. reset / subscribe / onAction)
- [六、Pinia vs Vuex(核心区别)](#六、Pinia vs Vuex(核心区别))
- 七、最佳实践
-

Pinia 是 Vue 官方推荐的新一代状态管理库 ,专为 Vue 3 设计(兼容 Vue 2),是 Vuex 的精神继任者。它以轻量、简洁、类型安全、模块化为核心优势,彻底简化 Vue 状态管理。
一、Pinia 核心介绍
1. 核心优势
- API 极简 :去掉 Vuex 的
mutations,同步/异步逻辑统一在actions处理 - 模块化扁平 :每个
store天然独立、无嵌套、无命名空间冲突 - TS 友好:原生类型推导,无需额外配置
- 极致轻量:gzip 后约 1KB,几乎无性能负担
- 组合式友好:完美适配 Vue 3 Composition API
- DevTools 集成:支持时间旅行、热更新、状态追踪
- SSR 支持:无缝兼容服务端渲染
2. 核心概念
- Store :全局状态仓库,用
defineStore创建 - State :存储响应式数据(类似组件
data) - Getters :基于 State 的计算属性(类似
computed) - Actions :修改 State 的方法(支持同步/异步,替代
mutations+actions)
二、Vue 3 中配置 Pinia
1. 安装
bash
npm install pinia
# 或
yarn add pinia
pnpm add pinia
2. 全局注册(main.ts/main.js)
typescript
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
const app = createApp(App)
const pinia = createPinia() // 创建 Pinia 实例
app.use(pinia) // 注册到 Vue
app.mount('#app')
三、Store 定义(两种风格)
方式 1:选项式(Options API,兼容 Vue 2)
typescript
// src/stores/counter.ts
import { defineStore } from 'pinia'
// 第一个参数:store 唯一 ID(必须全局唯一)
export const useCounterStore = defineStore('counter', {
// 1. 状态(必须箭头函数返回对象)
state: () => ({
count: 0,
name: 'Pinia Counter'
}),
// 2. 计算属性(带缓存)
getters: {
// 直接访问 state
doubleCount: (state) => state.count * 2,
// 访问其他 getter 用 this
doubleCountPlusOne(): number {
return this.doubleCount + 1
}
},
// 3. 动作(同步/异步,修改 state)
actions: {
// 同步
increment() {
this.count++
},
// 异步(async/await)
async incrementAsync(delay = 1000) {
await new Promise(resolve => setTimeout(resolve, delay))
this.count++
},
// 批量重置
reset() {
this.count = 0
this.name = 'Reset'
}
}
})
方式 2:组合式(Composition API,Vue 3 推荐)
typescript
// src/stores/user.ts
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
export const useUserStore = defineStore('user', () => {
// 1. 状态(ref/reactive 定义)
const userInfo = ref({ name: '', age: 0 })
const token = ref('')
const isLoading = ref(false)
// 2. 计算属性(computed 替代 getters)
const isAdult = computed(() => userInfo.value.age >= 18)
const userName = computed(() => userInfo.value.name || '未登录')
// 3. 动作(普通函数,同步/异步)
function setUser(info) {
userInfo.value = info
}
async function login(account, pwd) {
isLoading.value = true
try {
// 模拟接口请求
const res = await fetch('/api/login', {
method: 'POST',
body: JSON.stringify({ account, pwd })
})
const data = await res.json()
token.value = data.token
userInfo.value = data.user
return true
} catch (err) {
console.error('登录失败', err)
return false
} finally {
isLoading.value = false
}
}
// 必须返回暴露给组件
return {
userInfo,
token,
isLoading,
isAdult,
userName,
setUser,
login
}
})
四、组件中使用(<script setup>)
1. 基础使用
vue
<template>
<div>
<h2>{{ counter.name }}</h2>
<p>计数:{{ counter.count }}</p>
<p>双倍:{{ counter.doubleCount }}</p>
<p>双倍+1:{{ counter.doubleCountPlusOne }}</p>
<button @click="counter.increment">+1</button>
<button @click="counter.incrementAsync(1500)">异步+1</button>
<button @click="counter.reset">重置</button>
<!-- 解构(必须用 storeToRefs 保持响应式) -->
<p>解构计数:{{ count }}</p>
</div>
</template>
<script setup>
import { useCounterStore } from '@/stores/counter'
import { storeToRefs } from 'pinia'
// 1. 获取 store 实例
const counter = useCounterStore()
// 2. 响应式解构(关键!)
const { count, doubleCount } = storeToRefs(counter)
// 3. 直接修改(简单场景)
const setDirect = () => {
counter.count = 100
}
// 4. $patch 批量修改(推荐)
const batchUpdate = () => {
counter.$patch({
count: 50,
name: '批量更新'
})
// 函数形式(复杂逻辑)
counter.$patch((state) => {
state.count += 10
state.name = '函数批量'
})
}
</script>
2. 多 Store / 异步示例
vue
<template>
<div>
<p>用户:{{ userStore.userName }}</p>
<p>成年:{{ userStore.isAdult ? '是' : '否' }}</p>
<button @click="handleLogin" :disabled="userStore.isLoading">
{{ userStore.isLoading ? '登录中...' : '登录' }}
</button>
</div>
</template>
<script setup>
import { useUserStore } from '@/stores/user'
const userStore = useUserStore()
const handleLogin = async () => {
const success = await userStore.login('admin', '123456')
if (success) alert('登录成功!')
}
</script>
五、高级特性
1. 状态持久化(刷新不丢失)
安装插件:
bash
npm install pinia-plugin-persistedstate
注册(main.ts):
typescript
import { createPinia } from 'pinia'
import persist from 'pinia-plugin-persistedstate'
const pinia = createPinia()
pinia.use(persist) // 注册持久化
Store 开启:
typescript
export const useUserStore = defineStore('user', {
state: () => ({ token: '' }),
persist: true, // 全量持久化(localStorage)
// 或自定义
persist: {
key: 'app-user', // 存储 key
paths: ['token'], // 仅持久化 token
storage: sessionStorage // 切换存储
}
})
2. reset / subscribe / $onAction
typescript
// 重置 state(选项式)
counter.$reset()
// 监听 state 变化
counter.$subscribe((mutation, state) => {
console.log('状态变更', mutation, state)
})
// 监听 actions
counter.$onAction(({ name, after, onError }) => {
console.log('Action 开始:', name)
after(() => console.log('Action 完成'))
onError(err => console.error('Action 错误', err))
})
六、Pinia vs Vuex(核心区别)
| 特性 | Pinia | Vuex 3/4 |
|---|---|---|
| 核心概念 | state、getters、actions | state、getters、mutations、actions |
| 异步处理 | actions 直接支持 async/await | actions 提交 mutations |
| 模块化 | 天然扁平、独立 store | 嵌套 modules、命名空间 |
| TS 支持 | 原生、类型推导强 | 需额外配置、类型弱 |
| 体积 | ~1KB | 较大 |
| 组合式 | 完美适配 | 适配一般 |
七、最佳实践
- 按业务拆分 Store:user、cart、setting、layout 等
- 解构必用 storeToRefs:避免丢失响应式
- 复杂修改用 $patch:批量更新、性能更优
- 异步放 actions:统一逻辑、便于调试
- 非共享状态用组件内 ref:不要滥用全局状态