Pinia 状态管理原理与实战全解析

作者:90后晨仔日期:2025/10/19

一、前言:为什么选择 Pinia?

在 Vue2 时代,我们常用 Vuex 来做全局状态管理。

但是 Vue3 带来了全新的响应式系统(Composition API + Proxy),于是 Vue 官方团队推出了 Pinia —— 一款更轻量、更现代、更易用的状态管理库。

Pinia 的核心理念是:

“让状态管理像使用普通变量一样简单。”

相比 Vuex,它具备以下优势:

特点VuexPinia
语法基于 Mutations/Actions直接使用函数
类型推导较弱TypeScript 支持友好
响应式实现Object.definePropertyVue3 Proxy
模块化需手动命名空间天然支持模块化
体积较大小巧轻量(约1KB)

二、Pinia 的核心原理

要理解 Pinia,先要知道它是如何在底层维持响应式的。

1. 状态的本质:Reactive

Pinia 使用 Vue3 的 reactive() 来存储状态。

每个 store 内部其实就是一个被 reactive 包裹的对象。

1import { reactive } from 'vue'
2
3const state = reactive({
4  count: 0
5})
6

当 state.count++ 改变时,所有引用它的组件都会自动更新。

这就是 Pinia 响应式的根本机制。

2. Getter 的本质:Computed

在 Pinia 中,getter 相当于 Vue 中的 computed。

1getters: {
2  doubleCount: (state) => state.count * 2
3}
4

Pinia 会在内部把它转成一个 计算属性,只有依赖变化时才会重新计算。

因此它是 响应式、缓存式 的。

3. Action 的本质:普通函数 + 作用域代理

Pinia 不再强制使用 Mutation。

Action 其实就是对状态修改的封装函数。

1actions: {
2  increment() {
3    this.count++
4  }
5}
6

Pinia 通过 Proxy 让 this 指向 store 实例,因此你可以像访问普通对象一样修改状态。

4. 模块与依赖收集机制

每一个 store 都是一个独立的响应式作用域(Reactive Scope)。

Pinia 会将它注册到全局的 store 容器中(类似一个 Map 结构),并在组件使用时完成依赖收集。

组件一旦引用某个 store 的状态,Pinia 就会追踪它的依赖关系。

当 store 内的状态改变时,Pinia 会自动触发依赖更新 —— 这就是响应式传播的原理。


三、Pinia 的安装与配置

1️⃣ 安装

1npm install pinia
2# 或者
3yarn add pinia
4

2️⃣ 创建与挂载

在 main.js 中引入 Pinia 并挂载到 Vue 应用:

1import { createApp } from 'vue'
2import { createPinia } from 'pinia'
3import App from './App.vue'
4
5const app = createApp(App)
6app.use(createPinia())
7app.mount('#app')
8

四、定义第一个 Store

Pinia 推荐使用 defineStore() 来定义一个 store。

1// src/stores/counter.js
2import { defineStore } from 'pinia'
3
4export const useCounterStore = defineStore('counter', {
5  // 1. state:存放共享数据
6  state: () => ({
7    count: 0,
8    name: 'Pinia示例'
9  }),
10
11  // 2. getters:相当于计算属性
12  getters: {
13    doubleCount: (state) => state.count * 2
14  },
15
16  // 3. actions:用于定义修改逻辑
17  actions: {
18    increment() {
19      this.count++
20    },
21    setCount(val) {
22      this.count = val
23    }
24  }
25})
26

五、在组件中使用 Store

在组件中使用时,就像普通变量一样简单。

1<template>
2  <div>
3    <h2>{{ counter.name }}</h2>
4    <p>当前数量:{{ counter.count }}</p>
5    <p>双倍数量:{{ counter.doubleCount }}</p>
6    <button @click="counter.increment">增加</button>
7  </div>
8</template>
9
10<script setup>
11import { useCounterStore } from '@/stores/counter'
12
13const counter = useCounterStore()
14</script>
15

💡 响应式自动生效:

当 counter.count 改变时,界面会自动更新,无需手动刷新。


六、解构与响应式陷阱

Pinia store 是响应式对象,如果你用结构赋值要注意保持响应性。

错误写法 ❌:

1const { count } = useCounterStore()
2console.log(count) // 不会响应更新
3

正确写法 ✅:

1import { storeToRefs } from 'pinia'
2
3const store = useCounterStore()
4const { count, doubleCount } = storeToRefs(store)
5

storeToRefs() 会帮你保留响应式引用。


七、模块化管理多个 Store

Pinia 天然支持多 store,无需命名空间:

1// user.js
2export const useUserStore = defineStore('user', {
3  state: () => ({
4    name: '张三',
5    token: ''
6  }),
7  actions: {
8    login(name) {
9      this.name = name
10      this.token = 'token123'
11    }
12  }
13})
14

在组件中可以自由组合使用:

1import { useUserStore } from '@/stores/user'
2import { useCounterStore } from '@/stores/counter'
3
4const user = useUserStore()
5const counter = useCounterStore()
6

八、持久化存储(localStorage)

Pinia 本身不带持久化功能,但可以通过插件轻松实现:

✅ 手动持久化:

1watch(
2  () => store.count,
3  (newVal) => {
4    localStorage.setItem('count', newVal)
5  }
6)
7

✅ 使用插件(推荐):

安装:

1npm i pinia-plugin-persistedstate
2

注册插件:

1import { createPinia } from 'pinia'
2import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
3
4const pinia = createPinia()
5pinia.use(piniaPluginPersistedstate)
6

开启持久化:

1export const useUserStore = defineStore('user', {
2  state: () => ({ name: '', token: '' }),
3  persist: true
4})
5

九、Pinia + TypeScript 实践(简要示例)

Pinia 的类型推导非常强大。

在 TS 项目中可直接推断出 state 和 getter 的类型。

1export const useTodoStore = defineStore('todo', {
2  state: () => ({
3    list: [] as string[]
4  }),
5  actions: {
6    addTodo(item: string) {
7      this.list.push(item)
8    }
9  }
10})
11
12// 自动推导类型
13const store = useTodoStore()
14store.addTodo('学习 Pinia')
15

十、Pinia 内部运行机制简述

Pinia 内部核心模块包括:

  1. Store 实例注册
    每个 defineStore() 都注册到全局 pinia._s 容器中。
  2. Reactive 封装
    使用 reactive() 包装 state,配合 Vue 的 effect 机制实现依赖收集。
  3. Getter 包装为 computed
    保证 getter 的懒计算与缓存特性。
  4. Action 包装代理
    使用 Proxy 代理 this 指向当前 store,并自动注入 devtools 日志。
  5. 订阅机制
    Pinia 提供 store.$subscribe(),可以监听 state 变化。

十一、实战示例:Todo 应用

1<template>
2  <div>
3    <h2>我的待办事项</h2>
4    <input v-model="newTask" @keyup.enter="addTodo" placeholder="输入任务..."/>
5    <ul>
6      <li v-for="(item, index) in todos.list" :key="index">
7        {{ item }}
8        <button @click="removeTodo(index)">删除</button>
9      </li>
10    </ul>
11  </div>
12</template>
13
14<script setup>
15import { ref } from 'vue'
16import { useTodoStore } from '@/stores/todo'
17
18const todos = useTodoStore()
19const newTask = ref('')
20
21const addTodo = () => {
22  if (newTask.value.trim()) {
23    todos.addTodo(newTask.value)
24    newTask.value = ''
25  }
26}
27const removeTodo = (i) => todos.list.splice(i, 1)
28</script>
29

十二、总结

内容关键点
状态管理核心Vue3 的 reactive 与 computed
改进点无需 mutation、天然模块化
类型支持友好且强大
响应式机制Proxy + Effect 依赖追踪
持久化插件 pinia-plugin-persistedstate
适用场景中大型 Vue3 项目,全局状态同步

Pinia 的设计哲学是:

“简单到你几乎忘了自己在用状态管理库。”


Pinia 状态管理原理与实战全解析》 是转载文章,点击查看原文


相关推荐


图解AI核心技术:大模型、RAG、智能体、MCP
京东云开发者2025/10/17

简介 本文整理了来自Daily Dose of Data Science最热门或最新的文章,其中极具特色的动图以生动形象的方式,帮助我们更好的理解AI中的一些核心技术,希望能够帮助大家更好的理解和使用AI。 大模型 Transformer vs. Mixture of Experts 混合专家 (MoE) 是一种流行的架构,它使用不同的“专家”来改进 Transformer 模型。 下图解释了它们与 Transformers 的区别。 Transformer 使用前馈网络。 MoE 使用专家


一次慢接口背后,竟藏着40+种可能!你中过几个
uzong2025/10/16

从客户端到数据库的全链路性能瓶颈系统性排查指南 本文系统梳理了导致接口响应缓慢的40余种潜在原因,涵盖网络、网关、JVM、数据库、中间件等多个层面,旨在帮助开发者建立完整的性能问题排查思维模型,适用于线上故障定位与技术面试准备 作者:面汤放盐(公众号) || uzong 时间:2025-10-15 转载请备注声明 为什么会问这个问题 问题:现在生产上有一个慢接口,请分析一下这个慢接口,可能是系统中哪些环节导致的,大致原因是什么,可以是一些很细的案例,系统性的分析一下,越多越好,注意仅从理论


本地搭建 Jekyll 环境
爪娃侠2025/10/15

1、安装依赖 Windows:安装RubyInstaller(勾选「Add Ruby to PATH」)Mac:自带 Ruby,需更新 gem:sudo gem update --systemLinux:sudo apt-get install ruby-full 我个人Mac电脑安装时出现版本报错: 原因: macOS 系统自带的 Ruby 版本过低(当前是 2.6.10),而新版rubygems-update要求 Ruby 版本≥3.2.0,导致直接更新失败。 解决:用Ruby 版本管理工具


Hello 算法:让前端人真正理解算法
灵感__idea2025/10/13

每个系列一本前端好书,帮你轻松学重点。 本系列来自上海交通大学硕士,华为高级算法工程师 靳宇栋 的 《Hello,算法》 程序员圈儿有两种怪象: 1、人人称工程师,但少有人能真正担起一项“工程”。 2、掌握算法本是理所应当,实际寥寥无几。 一直以来,算法好像跟前端开发没多少关联,顶多用来应付面试。 本系列要做的,就是同大家一起啃下这块硬骨头,真正理解算法。 算法是什么 算法是什么,没有标准答案。 先看几个实际案例: 查字典 在字典里,每个汉字都对应一个拼音,而字典是按照字母顺序排列的。 查找”


深入浅出 C# MVC:从基础实践到避坑指南(附完整代码示例)
William_cl2025/10/12

目录 1. 引言:C# MVC 为何仍是企业级开发的优选?2. C# MVC 核心知识树(附可视化图谱)3. 实战上手:从零搭建学生管理系统(完整代码)3.1 第一步:创建 MVC 项目3.2 Model 层:定义数据实体与验证规则3.3 Controller 层:处理请求与业务逻辑3.4 View 层:渲染页面与用户交互3.4.1 列表页(Index.cshtml)3.4.2 添加表单页(Create.cshtml) 3.5 运行效果 4. 开发必避:5 个高频 “坑点” 及解


【Node】认识一下Node.js 中的 VM 模块
你的人类朋友2025/10/10

前言 今天介绍 Node.js 中的 VM(Virtual Machine)模块的基本概念和使用方法。 很多人不太了解他,比如在下 所以本文也不会过于深入,会偏向入门! 小目标:看完之后向自己解释一下:啥是 VM 模块?它有什么作用? 什么是 VM 模块 VM 模块是 Node.js 内置的模块,用于在 V8 虚拟机上下文中编译和执行 JavaScript 代码。 说人话就是,VM 模块允许你在隔离的环境中运行 JavaScript 代码。 核心功能 这边用代码进行举例子,后面会介绍具体的使用


OSI 七层模型
日更嵌入式的打工靓仔2025/10/9

一、OSI 七层模型的核心定位与价值​ OSI 七层模型(Open Systems Interconnection Reference Model)是国际标准化组织(ISO)于 1984 年制定的网络通信体系结构标准,其核心目标是打破不同厂商设备的通信壁垒,通过分层化设计实现 “功能解耦、接口标准化”。该模型将网络通信的复杂流程拆解为七个逻辑层次,每层通过定义明确的 “服务原语”(Service Primitive)为上层提供服务,并通过 “协议数据单元(PDU)” 与下层交互,确保不同系统间


【前端工程化】脚手架篇 - 模板引擎 & 动态依赖管理脚手架
ObjectX不知名程序员2025/10/7

🧑‍💻 写在开头 点赞 + 收藏 === 学会🤣🤣🤣 在日常工作中,我们经常为会遇到需要创建新项目的需求,为了统计代码风格,项目配置,提升效率,我们可以创建一个cli工具,帮助我们实现这样的功能。你也可以搭建一个自己用,毕竟省下来的时间都是自己的 🥑 你能学到什么? 希望在你阅读本篇文章之后,不会觉得浪费了时间。如果你跟着读下来,你将会学到: cli工具的基本搭建流程 如何通过模板引擎实现可选依赖 模板系统如何设计 如何根据模板引擎生成所需项目 熟悉一个组件库的基本结构 熟悉一


在AI技术快速实现创意的时代,挖掘游戏开发框架新需求成为关键
qife1222025/10/6

内容描述 核心功能定位:该项目是一个专为经典游戏主机设计的增强型JavaScript运行环境,旨在为用户提供完整的自制软件开发工具包。它通过简化开发流程,让开发者能够使用JavaScript这一简单语言创建游戏和应用程序,无需编译过程,只需编写脚本即可快速测试。 关键应用场景:主要应用于经典游戏主机的自制软件开发,包括游戏创作、应用程序开发、图形渲染、音频处理、网络通信等多个领域。开发者可以利用该环境快速原型设计和开发各类交互式内容。 功能特性 多模块支持:系统提供丰富的功能模块,


【Matlab】matlab代码实现最小凸包
智慧浩海2025/10/4

实现最小凸包的算法有多种方法,其中一种常见的方法是使用Graham扫描算法。下面是用Matlab实现Graham扫描算法找到最小凸包的示例代码: function [convexHull] = grahamScan(points) % 找到包含所有点的最小凸包 n = length(points); % 找到y坐标最小的点作为起始点 [~,idx] = min(points(:,2)); startPoint = points(idx,:);

首页编辑器站点地图

Copyright © 2025 聚合阅读

License: CC BY-SA 4.0