文章目录
-
- [一、Pinia 是什么?](#一、Pinia 是什么?)
-
- [Pinia 核心优势](#Pinia 核心优势)
- [二、Pinia 三大核心概念](#二、Pinia 三大核心概念)
-
- [1. State:全局数据源](#1. State:全局数据源)
- [2. Getters:数据计算属性](#2. Getters:数据计算属性)
- [3. Actions:数据修改方法](#3. Actions:数据修改方法)
- [三、Vue3 + Setup 语法完整使用步骤](#三、Vue3 + Setup 语法完整使用步骤)
-
- [1. 安装 Pinia](#1. 安装 Pinia)
- [2. 全局注册(main.js)](#2. 全局注册(main.js))
- [3. 定义 Store(核心步骤)](#3. 定义 Store(核心步骤))
- [4. 组件中使用 Store](#4. 组件中使用 Store)
- [四、修改 State 的 4 种方式(官方推荐 Actions)](#四、修改 State 的 4 种方式(官方推荐 Actions))
-
- [1. 直接修改(简单场景)](#1. 直接修改(简单场景))
- [2. 批量修改(patch)](#2. 批量修改(patch))
- [3. Actions 方法(官方推荐)](#3. Actions 方法(官方推荐))
- [4. 重置数据(reset)](#4. 重置数据(reset))
- [五、核心工具:storeToRefs 详解](#五、核心工具:storeToRefs 详解)
-
- 一句话总结
- [与 toRefs 的区别](#与 toRefs 的区别)
- [六、进阶技巧 1:subscribe 状态监听](#六、进阶技巧 1:subscribe 状态监听)
- [七、进阶技巧 2:Store 组合式写法](#七、进阶技巧 2:Store 组合式写法)
-
- [1. 定义组合式 Store](#1. 定义组合式 Store)
- [2. 组件中使用(与选项式一致)](#2. 组件中使用(与选项式一致))
- 组合式写法对应关系
- 八、总结
在 Vue3 开发中,组件间的状态共享一直是核心痛点------props 层层传参繁琐、事件总线难以维护,而 Pinia 就是 Vue 官方推荐的新一代全局状态管理库,完美替代 Vuex,轻量化、易上手、功能强大。
一、Pinia 是什么?
Pinia 是 Vue 的专属全局数据仓库 ,核心作用就是:存放多个组件共用的数据,让所有组件都能直接读写,告别繁琐传参。
简单来说:只要多个组件需要共用、修改同一份数据(用户信息、Token、购物车、主题配置等),直接用 Pinia 就对了!
Pinia 核心优势
- 轻量化:API 简洁,无冗余代码,学习成本极低
- 兼容性好:完美支持 Vue2/Vue3,搭配 Composition API 更丝滑
- 开箱即用:无需配置,安装注册后直接使用
- 开发友好:自带热更新,调试方便
- 功能强大:同步/异步修改数据一体化,支持数据持久化、状态监听
二、Pinia 三大核心概念
Pinia 只有三个核心模块,比 Vuex 更精简,记忆零负担:
1. State:全局数据源
存储所有全局共享的原始数据 ,相当于组件的 data,是状态管理的核心。
2. Getters:数据计算属性
对 State 中的数据进行过滤、加工、计算 ,自带缓存特性,相当于组件的 computed,数据不变时不会重复计算。
3. Actions:数据修改方法
唯一推荐修改 State 的方式 ,支持同步、异步操作(直接替代 Vuex 的 mutation + action),相当于组件的 methods。
三、Vue3 + Setup 语法完整使用步骤
1. 安装 Pinia
bash
npm install pinia
2. 全局注册(main.js)
在项目入口文件挂载 Pinia,让全局组件都能使用:
javascript
import { createApp } from 'vue'
import App from './App.vue'
// 引入 Pinia 核心方法
import { createPinia } from 'pinia'
const app = createApp(App)
// 挂载 Pinia
app.use(createPinia())
app.mount('#app')
3. 定义 Store(核心步骤)
新建 src/stores 目录(专门存放状态仓库),创建业务对应的 store 文件(如 user.js 管理用户信息)。
Pinia 支持两种写法:选项式写法 (类 Vuex 写法,易上手)、组合式写法(类 Setup 写法,更灵活),先学最常用的选项式:
javascript
// src/stores/user.js
import { defineStore } from 'pinia'
// 定义仓库:defineStore(仓库唯一ID, 配置对象)
export const useUserStore = defineStore('user', {
// 1. State:必须是函数,返回数据对象(避免数据污染)
state: () => ({
name: '张三',
age: 18,
token: ''
}),
// 2. Getters:计算属性,加工数据
getters: {
// 年龄+10,自动接收 state 为参数
addAge: (state) => state.age + 10,
// 拼接用户名
fullName: (state) => `当前用户:${state.name}`
},
// 3. Actions:修改数据的方法(同步/异步都支持)
actions: {
// 同步修改用户名
updateName(name) {
// 直接通过 this 访问 state 数据
this.name = name
},
// 异步修改(支持接口请求)
async userLogin() {
// 模拟接口请求
const res = await fetch('/api/login')
this.token = 'admin_token_123'
},
// 重置数据为默认值
resetStore() {
this.$reset()
}
}
})
4. 组件中使用 Store
在任意组件中,直接引入并使用,读写数据超简单:
vue
<script setup>
// 1. 引入定义好的仓库
import { useUserStore } from '@/stores/user'
// 2. 创建 store 实例
const userStore = useUserStore()
// 3. 解构数据:必须用 storeToRefs 保持响应式!
import { storeToRefs } from 'pinia'
const { name, age, addAge, fullName } = storeToRefs(userStore)
// 4. 方法直接解构使用(无需 storeToRefs)
const { updateName, userLogin, resetStore } = userStore
</script>
<template>
<div>
<p>用户名:{{ name }}</p>
<p>原始年龄:{{ age }}</p>
<p>计算后年龄:{{ addAge }}</p>
<p>格式化用户名:{{ fullName }}</p>
<!-- 调用方法修改数据 -->
<button @click="updateName('李四')">修改用户名</button>
<button @click="userLogin">模拟登录</button>
<button @click="resetStore">重置数据</button>
</div>
</template>
四、修改 State 的 4 种方式(官方推荐 Actions)
修改 State 有 4 种方式,优先使用 Actions,符合最佳实践,便于维护:
1. 直接修改(简单场景)
适合单个数据快速修改:
javascript
userStore.name = '李四'
2. 批量修改($patch)
适合一次性修改多个数据,性能更优:
javascript
userStore.$patch({
name: '李四',
age: 20
})
3. Actions 方法(官方推荐)
统一管理修改逻辑,支持异步,便于调试和维护:
javascript
userStore.updateName('李四')
4. 重置数据($reset)
一键恢复 State 为初始默认值:
javascript
userStore.$reset()
五、核心工具:storeToRefs 详解
一句话总结
只将 Store 中的 State、Getters 转为响应式 ref,自动过滤 Actions 方法,解构后不丢失响应式。
与 toRefs 的区别
toRefs:全量转换,会把方法也转为 ref,不适合 PiniastoreToRefs:智能筛选,只转换数据,跳过方法,是 Pinia 专属工具
六、进阶技巧 1:$subscribe 状态监听
$subscribe 可以监听整个 Store 的 State 变化 ,只要数据修改就触发回调,最常用的场景是数据持久化(缓存到本地存储)。
使用示例
javascript
const userStore = useUserStore()
// 订阅状态变化
const cancelSubscribe = userStore.$subscribe((info, state) => {
// info:修改信息(类型、参数)
// state:最新的 State 数据
// 持久化到 localStorage
localStorage.setItem('userInfo', JSON.stringify(state))
})
// 取消监听(按需使用)
// cancelSubscribe()
核心要点
- 批量
$patch修改多个值,只触发 1 次监听 ,优于多个watch - 默认组件销毁时自动取消监听,配置
{ detached: true }可全局常驻 - 仅监听 State 变化,Getters/Actions 变动不触发
七、进阶技巧 2:Store 组合式写法
组合式写法完全对标 Vue3 Setup 语法 ,用 ref/reactive 定义 State,普通函数定义 Actions,灵活性更高,适合复杂业务。
1. 定义组合式 Store
javascript
// src/stores/user.js
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
export const useUserStore = defineStore('user', () => {
// 1. ref/reactive = State 响应式数据
const name = ref('张三')
const age = ref(18)
const token = ref('')
// 2. computed = Getters 计算属性
const addAge = computed(() => age.value + 10)
const fullName = computed(() => `当前用户:${name.value}`)
// 3. 普通函数 = Actions 方法
const updateName = (val) => {
name.value = val
}
const userLogin = async () => {
const res = await fetch('/api/login')
token.value = 'admin_token_123'
}
const resetStore = () => {
name.value = '张三'
age.value = 18
token.value = ''
}
// 必须 return,组件才能访问
return { name, age, token, addAge, fullName, updateName, userLogin, resetStore }
})
2. 组件中使用(与选项式一致)
javascript
import { useUserStore } from '@/stores/user'
import { storeToRefs } from 'pinia'
const userStore = useUserStore()
// 解构响应式数据
const { name, age, addAge } = storeToRefs(userStore)
// 解构方法
const { updateName } = userStore
组合式写法对应关系
ref / reactive→ State(响应式数据源)computed→ Getters(数据计算属性)- 普通函数 → Actions(数据修改方法)
return→ 暴露给组件使用
八、总结
- Pinia 是 Vue 全局状态管理神器,核心是 State、Getters、Actions 三大模块
- 基础使用:安装 → 注册 → 定义 Store → 组件使用
- 修改数据优先用 Actions ,解构数据用 storeToRefs
- 进阶能力:
$subscribe监听状态、组合式写法适配复杂业务 - 无痛替代 Vuex,是 Vue3 项目状态管理的最佳选择