当前位置: 首页 > news >正文

前端学习教程-Pinia 教程

Pinia 是 Vue 官方推荐的状态管理库,替代了传统的 Vuex,专为 Vue3 设计,支持 Composition API 和 TypeScript,API 更简洁,是目前 Vue 项目状态管理的最佳选择。

一、为什么选择 Pinia?

与 Vuex 相比,Pinia 具有以下优势:

  • 无需 mutations,直接在 actions 中修改状态
  • 完美支持 Vue3 的 Composition API
  • 内置 TypeScript 支持,类型推断更友好
  • 简化的 API,学习成本更低
  • 支持多个 Store 实例,无需嵌套模块
  • 更轻量(约 1KB)

二、安装 Pinia

在 Vue3 项目中安装 Pinia:

npm install pinia --save
# 或
yarn add pinia

三、初始化 Pinia

首先需要在项目入口文件中创建 Pinia 实例并挂载到 Vue 应用(main.js):

import { createApp } from 'vue'
import App from './App.vue'
import { createPinia } from 'pinia'  // 导入 createPinia// 创建 Pinia 实例
const pinia = createPinia()// 创建应用并使用 Pinia
createApp(App).use(pinia)  // 挂载 Pinia.mount('#app')

四、核心概念与基础使用

1. 创建第一个 Store

Store 是 Pinia 的核心,用于存储全局状态。使用 defineStore() 创建 Store,它接收两个参数:

  • 第一个参数:Store 的唯一 ID(字符串)
  • 第二个参数:配置对象(包含 stategettersactions
import { defineStore } from 'pinia'// 定义并导出 Store
export const useCounterStore = defineStore('counter', {// 状态:存储数据的地方state: () => ({count: 0,name: '计数器'}),// 计算属性:基于 state 派生的数据getters: {// 基本使用doubleCount: (state) => state.count * 2,// 使用其他 getters(通过 this)doubleCountPlusOne() {return this.doubleCount + 1},// 带参数的 getter(返回函数)getCountWithAdd: (state) => (num) => state.count + num},// 方法:处理业务逻辑(支持同步和异步)actions: {increment() {// 直接修改 state(无需 mutations)this.count++},decrement() {this.count--},// 带参数的 actionincrementBy(num) {this.count += num},// 异步 action(如请求 API)async fetchData() {const res = await fetch('https://api.example.com/count')const data = await res.json()this.count = data.count}}
})

2. 在组件中使用 Store

在组件中通过创建的 useCounterStore 函数获取 Store 实例,然后访问其 stategettersactions

(1)使用 Composition API(推荐)

<template><div class="counter"><h2>{{ counterStore.name }}</h2><p>当前计数:{{ counterStore.count }}</p><p>计数翻倍:{{ counterStore.doubleCount }}</p><p>计数翻倍+1:{{ counterStore.doubleCountPlusOne }}</p><p>计数+5:{{ counterStore.getCountWithAdd(5) }}</p><button @click="counterStore.increment">+1</button><button @click="counterStore.decrement">-1</button><button @click="counterStore.incrementBy(10)">+10</button><button @click="counterStore.fetchData">从API获取数据</button></div>
</template><script setup>
// 导入 Store
import { useCounterStore } from '../stores/counterStore'// 获取 Store 实例(注意:不要解构,会失去响应性)
const counterStore = useCounterStore()
</script>

(2)使用 Options API

如果使用 Options API,可以通过 mapStatemapGettersmapActions 辅助函数映射 Store:

<template><div><p>计数:{{ count }}</p><p>翻倍:{{ doubleCount }}</p><button @click="increment">+1</button></div>
</template><script>
import { useCounterStore } from '../stores/counterStore'
import { mapState, mapGetters, mapActions } from 'pinia'export default {computed: {// 映射 state...mapState(useCounterStore, ['count', 'name']),// 映射 getters...mapGetters(useCounterStore, ['doubleCount'])},methods: {// 映射 actions...mapActions(useCounterStore, ['increment', 'decrement'])}
}
</script>

五、修改 State 的多种方式

Pinia 允许通过多种方式修改 state,比 Vuex 更灵活:

1. 直接修改(最简单)

const counterStore = useCounterStore()
counterStore.count++  // 直接修改
counterStore.name = '新计数器'  // 直接修改

2. 使用 $patch 批量修改

适合同时修改多个状态:

// 对象形式
counterStore.$patch({count: 10,name: '批量修改后的计数器'
})// 函数形式(更灵活,支持复杂逻辑)
counterStore.$patch((state) => {state.count += 5state.name = '函数修改的计数器'
})

3. 通过 actions 修改

适合包含业务逻辑的修改(推荐):

// 在 Store 中定义 action
actions: {resetAndSet(num) {this.count = 0  // 重置this.count += num  // 再修改this.name = '通过action修改'}
}// 在组件中调用
counterStore.resetAndSet(10)

4. 替换整个 State

使用 $state 替换整个状态对象:

counterStore.$state = {count: 100,name: '全新状态'
}

六、异步 Actions 详解

Pinia 的 actions 支持异步操作(如 API 请求),无需像 Vuex 那样区分 actionsmutations

import { defineStore } from 'pinia'
import axios from 'axios'export const useUserStore = defineStore('user', {state: () => ({userInfo: null,loading: false,error: null}),actions: {// 登录(异步操作)async login(username, password) {try {this.loading = truethis.error = null// 调用 APIconst res = await axios.post('/api/login', {username,password})// 存储用户信息this.userInfo = res.data.user// 保存 token 到本地存储localStorage.setItem('token', res.data.token)return res.data  // 返回结果给组件} catch (err) {this.error = err.response?.data?.message || '登录失败'throw err  // 抛出错误,让组件可以捕获} finally {this.loading = false  // 无论成功失败,都结束加载}},// 退出登录logout() {this.userInfo = nulllocalStorage.removeItem('token')},// 获取用户信息async fetchUserInfo() {try {this.loading = trueconst token = localStorage.getItem('token')const res = await axios.get('/api/user', {headers: { Authorization: `Bearer ${token}` }})this.userInfo = res.data} catch (err) {this.error = '获取用户信息失败'} finally {this.loading = false}}}
})

在组件中使用异步 action:

<script setup>
import { useUserStore } from '../stores/userStore'const userStore = useUserStore()const handleLogin = async () => {try {await userStore.login('admin', '123456')alert('登录成功')} catch (err) {alert(userStore.error)  // 显示错误信息}
}
</script>

七、Store 组合(跨 Store 调用)

在大型项目中,可能需要多个 Store 协同工作,Pinia 支持在一个 Store 中直接使用另一个 Store:

import { defineStore } from 'pinia'
import { useUserStore } from './userStore'  // 导入其他 Storeexport const useCartStore = defineStore('cart', {state: () => ({items: []}),getters: {totalPrice: (state) => {return state.items.reduce((total, item) => total + item.price * item.quantity, 0)},// 结合用户信息计算折扣价discountedPrice() {const userStore = useUserStore()  // 获取用户 Store// 会员打9折return userStore.userInfo?.isVip ? this.totalPrice * 0.9 : this.totalPrice}},actions: {addItem(product) {const userStore = useUserStore()// 未登录不能添加到购物车if (!userStore.userInfo) {throw new Error('请先登录')}this.items.push({ ...product, quantity: 1 })}}
})

八、持久化存储(状态持久化)

Pinia 本身不提供持久化功能,但可以通过 pinia-plugin-persistedstate 插件实现状态持久化(刷新页面后状态不丢失):

1. 安装插件

npm install pinia-plugin-persistedstate --save

2. 配置插件

// src/main.js
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'  // 导入插件
import App from './App.vue'const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)  // 使用插件createApp(App).use(pinia).mount('#app')

3. 在 Store 中启用持久化

export const useUserStore = defineStore('user', {state: () => ({ /* ... */ }),// 启用持久化persist: true,  // 默认为 localStorage 存储整个 state// 或自定义配置persist: {key: 'user-storage',  // 存储的键名storage: sessionStorage,  // 使用 sessionStoragepaths: ['userInfo']  // 只持久化 userInfo 字段}
})

九、最佳实践

  1. 按功能拆分 Store:避免创建单一的大 Store,按功能(如 userStorecartStoreproductStore)拆分
  2. 使用 Composition API:在组件中优先使用 setup() 语法,更符合 Vue3 生态
  3. 复杂逻辑放 actions:组件只负责调用 actions,业务逻辑封装在 Store 中
  4. 避免过度使用全局状态:只有多个组件共享的数据才需要放入 Store,组件内部数据用 ref/reactive
  5. TypeScript 类型定义:为 state 和 actions 参数添加类型,提升开发体验

总结

Pinia 是 Vue3 状态管理的最佳选择,其简洁的 API 和对 Composition API 的完美支持,让状态管理变得简单直观。通过本教程,你已掌握:

  • Pinia 的安装与初始化
  • Store 的创建(state、getters、actions)
  • 状态修改的多种方式
  • 异步 actions 的实现
  • Store 组合与持久化存储
http://www.hskmm.com/?act=detail&tid=24506

相关文章:

  • 布谷娱乐直播架构源码开发实用功能:技术驱动更迭的创新体验
  • Bean生命周期
  • 回忆QQ空间有感
  • mtgsig
  • 前端学习教程-Vue Router 教程
  • 详细介绍:Java-Spring 入门指南(十七)SpringMVC--Apipostl与RestFul实战测试
  • 详细介绍:告别 403 Forbidden!详解爬虫如何模拟浏览器头部(User-Agent)
  • 通过学习分位数函数提升预测准确性
  • 高中数列梳理
  • AtCoder Beginner Contest 426 实况记录 + A-D 题解
  • 提示词攻击如何防范(2025):从 Indirect Prompt Injection 到 RAG 供应链的分层防御实战
  • 【STM32项目开源】基于STM32的智能养殖场环境监测系统 - 详解
  • 前端学习教程-Axios
  • 『回忆录』返校前夜 230102
  • 断更
  • 前端学习教程-环境配置
  • TypeScript - Ref
  • 20251004 qmd 弱化规约(未完成)
  • 深入解析:人工智能专业术语详解(C)
  • 2025.10.4模拟赛
  • 黄金替罪羊
  • P5301 [GXOI/GZOI2019] 宝牌一大堆
  • 10.4 2025多校冲刺CSP模拟赛2 改题记录
  • 【比赛记录】2025CSP-S模拟赛58
  • 回忆有感
  • 框架高效的系统的演进如何塑造人工智能的深层语义分析能力
  • 『回忆录』高二上第一次月考——压力下的崛起,意料外的突破
  • AutoCAD 2025安装包下载 CAD免费下载 永久免费激活 附详细安装教程
  • 微分和积分的区别
  • 202509_QQ_secret