Skip to content

D34. 状态管理 pinia

4.1. 🔄 状态共享简化冗余的组件间传递

传统组件通信痛点:父子组件通过 propsevents 传递数据,嵌套层级多时代码冗余且难以维护。

问题场景

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 的对比

特性VuexPinia
核心概念state/mutation/actions/gettersstate/actions/getters(无 mutation)
API 风格选项式配置为主组合式 API 优先,支持选项式
模块化需嵌套 modules每个 store 独立文件
体积较大(含冗余逻辑)极小(仅 1KB)
TypeScript 支持需额外配置原生深度支持

核心概念

  1. State(状态)

    javascript
    state: () => ({ count: 0 })
  2. Getters(派生状态)

    javascript
    getters: {
      doubleCount: (state) => state.count * 2
    }
  3. Actions(操作)

    javascript
    actions: {
      increment() { this.count++ }
    }
  4. $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>

知识回顾

  1. 核心优势
    • 状态集中管理 → 避免组件间数据耦合
    • 模块化设计 → 代码结构清晰
    • 简化 API → 无 mutation 分层
  2. 关键方法
    • $patch:批量更新状态
    • $reset:恢复初始状态
    • persist:数据持久化
  3. 对比要点
    • Pinia 与 Vue3 原生语法深度集成
    • 更小体积、更少配置、更好类型支持

课后练习

  1. 单选:以下哪个 Pinia 方法用于批量更新状态?

    • A. $reset()
    • B. $patch()
    • C. $persist()
    • D. $getters()
  2. 填空:Pinia 中通过______方法可以恢复 store 的初始状态。

  3. 简答:为什么说 Pinia 比 Vuex 更适合 Vue3 项目?

参考答案
  1. B
  2. $reset()
  3. Pinia 与 Vue3 的组合式 API 完美集成,去除了冗余的 mutation 分层,提供更简洁的 API 和更好的 TypeScript 支持。

扩展阅读

Built by Vitepress | Apache 2.0 Licensed