Vue3 状态管理库 Pinia 完整教程

你想系统学习 Vue3 官方推荐的状态管理库 Pinia,我会从核心概念、基础使用、模块化、异步操作到实战技巧,用最简单易懂的方式教你完全掌握。

一、核心概念

Pinia 是 Vue 官方新一代状态管理库,替代 Vuex,专为 Vue3 设计,同时兼容 Vue2,核心优势:

  • 语法简洁,无需 mutation(只有 state、getters、actions)
  • 天然支持 TypeScript
  • 模块化设计,无需嵌套模块
  • 体积更小,性能更高
  • 支持热更新、插件扩展

二、快速上手(步骤)

1. 安装 Pinia

bash 复制代码
# npm
npm install pinia

# yarn
yarn add pinia

# pnpm
pnpm add pinia

2. 在 main.js 全局注册

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')

三、定义 Store(核心)

Store 是存储状态和业务逻辑的容器,推荐按功能模块化拆分(如 user、cart、setting)。

1. 创建 Store 示例

在 src/stores/ 目录下新建文件(如 user.js):

javascript 复制代码
// src/stores/user.js
import { defineStore } from 'pinia'

// 第一个参数:store 唯一 ID(必须唯一)
// 第二个参数:配置对象
export const useUserStore = defineStore('user', {
  // 1. 状态:存储数据(类似 data)
  state: () => ({
    name: '张三',
    age: 20,
    token: ''
  }),

  // 2. 计算属性:派生状态(类似 computed,有缓存)
  getters: {
    // 自动接收 state 作为参数
    doubleAge: (state) => state.age * 2,
    // 也可以使用 this 访问整个 store
    getName: function() {
      return `我的名字:${this.name}`
    }
  },

  // 3. 方法:修改状态、异步请求(类似 methods)
  actions: {
    // 同步修改
    updateName(newName) {
      this.name = newName
    },
    // 异步修改(支持 async/await)
    async login(account, pwd) {
      // 模拟接口请求
      const res = await new Promise(resolve => {
        setTimeout(() => resolve({ token: 'abcd-1234' }), 1000)
      })
      this.token = res.token
      this.name = account
    }
  }
})

四、组件中使用 Store

1. 基础使用(读取/修改状态)

vue 复制代码
<template>
  <div>
    <p>姓名:{{ userStore.name }}</p>
    <p>年龄:{{ userStore.age }}</p>
    <p>双倍年龄:{{ userStore.doubleAge }}</p>
    <button @click="userStore.updateName('李四')">改名</button>
    <button @click="userStore.login('admin', '123456')">登录</button>
  </div>
</template>

<script setup>
// 导入定义好的 store
import { useUserStore } from './stores/user'

// 实例化 store
const userStore = useUserStore()
</script>

2. 解构 state(保持响应式)

直接解构会丢失响应式 ,必须用 storeToRefs:

javascript 复制代码
import { storeToRefs } from 'pinia'

// 正确写法:响应式解构
const { name, age, doubleAge } = storeToRefs(userStore)

// 注意:actions 不需要解构,直接用
const { updateName, login } = userStore

3. 批量修改 state

javascript 复制代码
// 方式1:单个修改
userStore.name = '王五'

// 方式2:批量修改(推荐)
userStore.$patch({
  name: '赵六',
  age: 25
})

// 方式3:函数式批量修改(适合复杂逻辑)
userStore.$patch(state => {
  state.name = '孙七'
  state.age += 1
})

4. 重置 state 到初始值

javascript 复制代码
userStore.$reset()

五、模块化与 Store 相互调用

Pinia 无需配置模块,直接导入其他 Store 即可使用。

示例:cart 购物车 store 调用 user store

javascript 复制代码
// src/stores/cart.js
import { defineStore } from 'pinia'
import { useUserStore } from './user'

export const useCartStore = defineStore('cart', {
  state: () => ({
    list: []
  }),
  actions: {
    addCart(goods) {
      const userStore = useUserStore()
      // 判断用户是否登录
      if (!userStore.token) {
        alert('请先登录')
        return
      }
      this.list.push(goods)
    }
  }
})

六、数据持久化(常用插件)

页面刷新后 Pinia 数据会丢失,使用 pinia-plugin-persistedstate 插件实现本地持久化。

1. 安装

bash 复制代码
pnpm add pinia-plugin-persistedstate

2. 全局注册

javascript 复制代码
// main.js
import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'

const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)

3. 开启持久化

javascript 复制代码
// 在 store 中添加 persist: true
export const useUserStore = defineStore('user', {
  state: () => ({ ... }),
  persist: true // 开启持久化(默认 localStorage)
})

七、完整实战总结

  1. 安装 + 全局注册 Pinia
  2. 按功能拆分 Store(user/cart 等)
  3. 用 state 存数据、getters 做计算、actions 做修改/异步
  4. 组件中导入使用,storeToRefs 解构保持响应式
  5. 跨模块调用直接导入其他 Store
  6. 用持久化插件保存数据不丢失

总结

  1. Pinia 是 Vue3 首选状态库,无 mutation、语法极简
  2. 核心三部分:state(数据)、getters(计算)、actions(方法)
  3. 响应式解构必须用 storeToRefs
  4. 模块化天然支持,持久化插件一键配置
相关推荐
粥里有勺糖4 小时前
安利一下最近用的桌面“Agent” | T3 Code
前端·github·ai编程
xy34534 小时前
Axure 9.0 动态面板基本操作
前端·ui·html·axure·原型·产品设计
不停喝水4 小时前
【前端转全栈java速通课】 项目实战④7-11节 操作数据库-登录-注册-修改密码-注销-mubatis-plus简化crud-
java·前端·数据库
一水鉴天5 小时前
统一对象拓扑(UOT)设计全链定稿:从三件事分离到三继承 之1 20261010(豆包“查看聊天内容”继续)
前端·css
栖凤5 小时前
Java 的 try-catch 在 Agent 里失效了,我用了 5 个模式才兜住
java·前端·python
粥里有勺糖5 小时前
视野修炼第136期 | 前端小恐龙"Deno"被收购
前端·github·ai编程
修炼的dance5 小时前
页面塞了13.88 MB字体,导出的PDF只有71 KB
前端
qq_369173635 小时前
如何将 AI 生成的 HTML 网页发布成在线链接?不用自己搭建服务器
前端·人工智能·html·效率工具·html 发布
风花一世月5 小时前
⚡ 我把一座含氢能源园区搬进了浏览器(五类能流实时算守恒,在线直接玩)
前端·人工智能
羲云5 小时前
Claude 越界事件之后:Agent 权限设计为什么不能只靠提示词
前端