D34. 状态管理 pinia
4.1. 🔄 状态共享简化冗余的组件间传递
传统组件通信痛点:父子组件通过
props
和events
传递数据,嵌套层级多时代码冗余且难以维护。
问题场景
javascript
// 父组件需要将 count 传递给多个子组件
<template>
<ChildA :count="count" @increment="count++" />
<ChildB :count="count" />
<ChildC :count="count" />
</template>
Pinia 解决方案
javascript
// 创建全局 store
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', {
state: () => ({ count: 0 }),
actions: {
increment() { this.count++ }
}
})
// 组件中直接使用
<template>
<div>{{ counter.count }}</div>
<button @click="counter.increment()">+1</button>
</template>
<script setup>
import { useCounterStore } from '@/stores/counter'
const counter = useCounterStore()
</script>
4.2. 🛠️ 状态管理增强封装特性
核心优势
- 模块化设计:每个 store 独立管理自身状态,避免命名冲突
- 组合式 API:与 Vue3 的
setup()
语法无缝集成 - TypeScript 支持:自动推导类型无需额外定义
- 轻量高效:仅 1KB 左右,无冗余配置
用例:模块化拆分
javascript
// store/modules/user.js
export const useUserStore = defineStore('user', {
state: () => ({ name: 'Vue' }),
actions: { login() { this.name = 'Logged' } }
})
// store/modules/cart.js
export const useCartStore = defineStore('cart', {
state: () => ({ items: [] }),
actions: { addToCart(item) { this.items.push(item) } }
})
4.3. 🌟 Pinia 是 Vue3 的状态管理方案
与 Vuex 的对比
特性 | Vuex | Pinia |
---|---|---|
核心概念 | state/mutation/actions/getters | state/actions/getters(无 mutation) |
API 风格 | 选项式配置为主 | 组合式 API 优先,支持选项式 |
模块化 | 需嵌套 modules | 每个 store 独立文件 |
体积 | 较大(含冗余逻辑) | 极小(仅 1KB) |
TypeScript 支持 | 需额外配置 | 原生深度支持 |
核心概念
State(状态)
javascriptstate: () => ({ count: 0 })
Getters(派生状态)
javascriptgetters: { doubleCount: (state) => state.count * 2 }
Actions(操作)
javascriptactions: { increment() { this.count++ } }
$patch 和 $reset
javascript// 批量更新 this.$patch({ count: 10, name: 'Vue3' }) // 恢复初始状态 this.$reset()
4.4. 🚀 Pinia 用例介绍
用例 1:基础计数器
javascript
// store/counter.js
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
const increment = () => count.value++
return { count, increment }
})
// 组件中使用
<script setup>
import { useCounterStore } from '@/stores/counter'
const counter = useCounterStore()
</script>
用例 2:持久化存储
javascript
// 安装插件
npm install pinia-plugin-persistedstate
// main.js
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)
// store/user.js
export const useUserStore = defineStore('user', {
state: () => ({
token: localStorage.getItem('token') || ''
}),
persist: true // 启用持久化
})
用例 3:跨组件状态共享
javascript
// store/global.js
export const useGlobalStore = defineStore('global', {
state: () => ({
theme: 'light',
isLogged: false
})
})
// 组件A设置主题
useGlobalStore().theme = 'dark'
// 组件B直接读取
<template>
<div :class="global.theme">{{ global.isLogged ? '欢迎回来' : '请登录' }}</div>
</template>
<script setup>
import { useGlobalStore } from '@/stores/global'
const global = useGlobalStore()
</script>
知识回顾
- 核心优势:
- 状态集中管理 → 避免组件间数据耦合
- 模块化设计 → 代码结构清晰
- 简化 API → 无
mutation
分层
- 关键方法:
$patch
:批量更新状态$reset
:恢复初始状态persist
:数据持久化
- 对比要点:
- Pinia 与 Vue3 原生语法深度集成
- 更小体积、更少配置、更好类型支持
课后练习
单选:以下哪个 Pinia 方法用于批量更新状态?
- A.
$reset()
- B.
$patch()
- C.
$persist()
- D.
$getters()
- A.
填空:Pinia 中通过______方法可以恢复 store 的初始状态。
简答:为什么说 Pinia 比 Vuex 更适合 Vue3 项目?
参考答案
- B
$reset()
- Pinia 与 Vue3 的组合式 API 完美集成,去除了冗余的 mutation 分层,提供更简洁的 API 和更好的 TypeScript 支持。