核心总结(一句话概括)

  • Vuex:Vue 官方曾经的状态管理标准解决方案,成熟稳定,概念清晰,但语法稍显冗长。
  • Pinia:Vue 官方推荐的新一代状态管理库,API 设计极其简洁,完美支持 TypeScript,且兼容 Vue 2 和 3。

Vuex 的优点

Vuex 是 Vue 生态中经过长时间考验的状态管理库,其优点主要体现在以下几个方面:

  1. 成熟稳定与广泛认可

    • Vuex 是 Vue 生态的“老大哥”,拥有悠久的历史和庞大的用户群体。这意味着你遇到的所有问题,几乎都能在社区找到答案和解决方案。
    • 经过无数大型项目的检验,其稳定性和可靠性毋庸置疑。
  2. 清晰的架构与流程

    • Vuex 强制使用单向数据流(State -> View -> Actions -> Mutations -> State),这使得状态变化变得可预测和易于追踪。
    • 明确的角色分工(State, Getters, Mutations, Actions)让代码结构非常清晰,特别适合团队协作,能有效规范开发者的代码书写方式。
  3. 强大的开发工具集成

    • Vue Devtools 对 Vuex 提供了完美的支持。你可以方便地进行时间旅行调试(Time Travel Debugging),查看每一次状态变更的详细记录、触发它的 mutation 和 action,甚至可以回退到某个历史状态,这对于调试复杂应用非常有用。
  4. 内置的模块化方案

    • Vuex 提供了完整的模块(Modules)系统,允许你将复杂的 store 分割成多个模块,每个模块拥有自己的 state、getters、mutations、actions,甚至可以嵌套子模块。这对于组织大型项目的代码非常有效。

Pinia 的优点

Pinia 由 Vue.js 核心团队开发和维护,被誉为“下一代的 Vuex”,它吸收了许多优秀 ideas,其优点非常突出:

  1. 极其简洁的 API 设计

    • Pinia 的 API 设计非常直观,大大减少了模板代码。它废除了 Vuex 中 Mutations 的概念,只需要 state, getters, actions
    • Actions 统一处理同步和异步操作,不再需要区分是 commit 一个 mutation 还是 dispatch 一个 action,心智负担显著降低。
  2. 完美的 TypeScript 支持

    • Pinia 的 API 从一开始就是为 TS 设计的,提供了出色的类型推断。你几乎不需要编写额外的类型定义,就能获得完整的自动补全和类型安全检查,开发体验极佳。
  3. 轻量级与高性能

    • Pinia 的体积非常小(约 1KB),对 bundle 大小的影响微乎其微。
    • 其设计上没有任何冗余,性能优秀。
  4. 模块化是天然设计

    • Pinia 没有嵌套模块的概念,而是鼓励你创建多个 store。每个 store 都是独立的,你可以按需导入使用。这种“扁平化”的设计使得代码结构更简单,同时仍然可以通过在 store 中导入另一个 store 来实现交叉组合(Cross Store),非常灵活。
  5. Composition API 风格

    • Pinia 的 API 设计与 Vue 3 的 Composition API 风格高度一致,使用 refcomputed 等函数来定义 state 和 getters,对于熟悉 Composition API 的开发者来说上手几乎没有成本。
  6. 无需复杂的模块注册

    • 在 Vuex 中,你需要先将模块注册到根 store。而在 Pinia 中,每个 store 都是独立定义和使用的,无需在根 store 中注册,简化了流程。
  7. 官方推荐与未来趋势

    • Pinia 已经成为 Vue 官方的正式项目,并被推荐为默认的状态管理解决方案。对于新项目,尤其是 Vue 3 项目,选择 Pinia 意味着你选择了未来的主流和方向。

对比表格

特性VuexPinia
适用版本Vue 2 / Vue 3Vue 2 / Vue 3
API 设计稍显冗长,概念多(Mutations/Actions)极其简洁,只有 state/getters/actions
TS 支持需要额外配置,支持一般完美支持,原生友好
调试工具完美支持(时间旅行)支持,但时间旅行功能尚不完善
学习曲线中等,需要理解特定概念低,更接近 Vue 组件开发思维
模块化通过 modules 实现嵌套模块通过多个 store 实现扁平化模块
包大小较大非常小 (~1KB)
官方地位旧版标准新一代官方推荐

如何选择?

  • 为新项目选择 Pinia:毫无疑问,对于新的 Vue 2 或 Vue 3 项目,都应该优先选择 Pinia。它更简单、更现代、对 TypeScript 更友好,而且是官方推荐的未来。
  • 维护现有 Vuex 项目:如果你的老项目使用的是 Vuex,并且运行良好,没有必要立刻重构成 Pinia。Vuex 4 仍然是一个稳定且功能完整的库,会继续得到维护。重构应该在有足够资源和明显收益时才进行。
  • 需要强大的时间旅行调试:如果你极度依赖 Vue Devtools 中的时间旅行调试功能来排查复杂问题,目前 Vuex 在这方面可能仍略有优势。不过 Pinia 的调试功能也在不断完善中。

总而言之,Pinia 在绝大多数场景下都是比 Vuex 更优的选择,它代表了 Vue 状态管理的未来方向。


好的,我们结合代码来深入对比 Vuex 和 Pinia 的用法和优点。我们将以实现一个简单的计数器(Counter)和一个异步获取用户信息(User)的功能为例。


1. Vuex 实现

项目结构(通常如此组织)
src/store/index.js          // 主入口,创建 root storemodules/counter.js     // 计数器模块user.js        // 用户模块
代码实现

1. 计数器模块 (store/modules/counter.js)

// 计数器模块
const state = {count: 0
};const getters = {doubleCount: (state) => state.count * 2,isEven: (state) => state.count % 2 === 0
};// Mutations 必须是同步函数
const mutations = {INCREMENT(state, payload) {state.count += payload;},DECREMENT(state, payload) {state.count -= payload;}
};// Actions 可以包含异步操作
const actions = {incrementAsync({ commit }, payload) {setTimeout(() => {commit('INCREMENT', payload.amount);}, 1000);}
};export default {// 开启命名空间,避免模块间命名冲突namespaced: true,state,getters,mutations,actions
};

2. 用户模块 (store/modules/user.js)

const state = {user: null,isLoading: false
};const getters = {userName: (state) => state.user?.name || 'Guest'
};const mutations = {SET_LOADING(state, isLoading) {state.isLoading = isLoading;},SET_USER(state, user) {state.user = user;}
};const actions = {async fetchUser({ commit }, userId) {commit('SET_LOADING', true);try {// 模拟异步 API 调用const response = await fetch(`https://api.example.com/users/${userId}`);const user = await response.json();commit('SET_USER', user);} catch (error) {console.error('Failed to fetch user:', error);} finally {commit('SET_LOADING', false);}}
};export default {namespaced: true,state,getters,mutations,actions
};

3. 创建 Store (store/index.js)

import { createStore } from 'vuex';
import counter from './modules/counter';
import user from './modules/user';export default createStore({modules: {counter,user}
});

4. 在 Vue 组件中使用 (Component.vue)

<template><div><h2>Counter: {{ count }}</h2><p>Double: {{ doubleCount }}, Is Even: {{ isEven }}</p><button @click="increment(1)">+1</button><button @click="incrementAsync(5)">+5 Async</button><h2>User: {{ userName }}</h2><button @click="fetchUser(123)" :disabled="isLoading">{{ isLoading ? 'Loading...' : 'Fetch User' }}</button></div>
</template><script>
import { mapState, mapGetters, mapActions } from 'vuex';export default {computed: {// 映射 counter 模块的 state 和 getters...mapState('counter', ['count']),...mapGetters('counter', ['doubleCount', 'isEven']),// 映射 user 模块的 state 和 getters...mapState('user', ['isLoading']),...mapGetters('user', ['userName'])},methods: {// 映射 counter 模块的 actions...mapActions('counter', ['incrementAsync']),// 映射 user 模块的 actions...mapActions('user', ['fetchUser']),// 直接提交 mutation (通常不推荐在组件中直接提交,应用 Action)increment(amount) {this.$store.commit('counter/INCREMENT', amount);}}
};
</script>
Vuex 代码特点分析:
  1. 概念清晰但繁琐:严格区分了 Mutations(同步)和 Actions(异步)。
  2. 模板代码多:需要定义 state, getters, mutations, actions 四个部分,即使逻辑很简单。
  3. 模块化需要注册:需要在主入口文件中注册模块。
  4. 命名空间:必须使用 namespaced: true 和类似 'counter/INCREMENT' 的路径来访问,字符串容易写错。
  5. TypeScript 支持较弱:需要大量手动类型定义才能获得良好的类型推断。

2. Pinia 实现

项目结构(更灵活,推荐按功能组织)
src/stores/counter.store.js     // 计数器 Storeuser.store.js        // 用户 Store
代码实现

1. 计数器 Store (stores/counter.store.js)

import { defineStore } from 'pinia';// 使用 'counter' 作为 store 的唯一 ID
export const useCounterStore = defineStore('counter', {// State 是一个函数,返回初始状态state: () => ({count: 0}),// Getters 等同于 store 的 computed 属性getters: {doubleCount: (state) => state.count * 2,isEven: (state) => state.count % 2 === 0},// Actions 可以是同步或异步的actions: {increment(amount) {// 在 Action 中直接修改 statethis.count += amount;},decrement(amount) {this.count -= amount;},async incrementAsync(amount) {// 异步操作同样简单await new Promise(resolve => setTimeout(resolve, 1000));this.increment(amount); // 可以调用其他 action}}
});

2. 用户 Store (stores/user.store.js)

import { defineStore } from 'pinia';export const useUserStore = defineStore('user', {state: () => ({user: null,isLoading: false}),getters: {userName: (state) => state.user?.name || 'Guest'},actions: {async fetchUser(userId) {this.isLoading = true;try {const response = await fetch(`https://api.example.com/users/${userId}`);this.user = await response.json();} catch (error) {console.error('Failed to fetch user:', error);} finally {this.isLoading = false;}}}
});

3. 创建并挂载 Pinia (main.js)

import { createApp } from 'vue';
import { createPinia } from 'pinia'; // 导入 createPinia
import App from './App.vue';// 1. 创建 Pinia 实例
const pinia = createPinia();// 2. 将 Pinia 实例挂载到 Vue 应用
createApp(App).use(pinia).mount('#app');
// 注意:这里没有像 Vuex 那样的“主 store”需要创建和注册模块

4. 在 Vue 组件中使用 (Component.vue)

<template><div><h2>Counter: {{ counterStore.count }}</h2><p>Double: {{ counterStore.doubleCount }}, Is Even: {{ counterStore.isEven }}</p><button @click="counterStore.increment(1)">+1</button><button @click="counterStore.incrementAsync(5)">+5 Async</button><h2>User: {{ userStore.userName }}</h2><button @click="userStore.fetchUser(123)" :disabled="userStore.isLoading">{{ userStore.isLoading ? 'Loading...' : 'Fetch User' }}</button></div>
</template><script setup>
// 1. 导入需要的 store
import { useCounterStore } from '@/stores/counter.store';
import { useUserStore } from '@/stores/user.store';// 2. 在 setup() 中调用它们
// Pinia 会自动处理依赖和单例,你可以在任何地方调用,它都会返回同一个实例。
const counterStore = useCounterStore();
const userStore = useUserStore();// 如果你需要解构 store 以保持响应性,可以使用 storeToRefs
// import { storeToRefs } from 'pinia';
// const { count, doubleCount } = storeToRefs(counterStore);
// const { isLoading, userName } = storeToRefs(userStore);
</script>
Pinia 代码特点分析:
  1. API 极其简洁:只有一个 defineStore 函数,包含 state, getters, actions 三个部分。废除了 mutations
  2. 直接修改状态:在 actions 中,可以直接通过 this.count 修改状态,无需 commit。同步和异步操作写法统一。
  3. TypeScript 完美支持:所有类型都是自动推断的。useCounterStore 具有完整的类型信息。
  4. 模块化是天然的:每个 store 都是一个独立的文件,通过 useXxxStore 函数按需引入和使用,无需在中心点注册。
  5. 与 Composition API 完美融合:在 <script setup> 中使用,感觉就像在使用一个组合式函数,非常自然。
  6. 无命名空间烦恼:每个 store 本身就是一个“命名空间”,直接通过 store.prop 访问,没有字符串路径。

总结对比

操作VuexPinia优势方
定义 Statestate: { count: 0 }state: () => ({ count: 0 })Pinia (函数式,更好的 TS 支持)
定义 Gettergetters: { double: (s) => s.count * 2 }getters: { double: (s) => s.count * 2 }平手
同步更新commit('INCREMENT', payload)this.count += payloadPinia (更直观,代码少)
异步操作dispatch('incrementAsync', payload)this.incrementAsync(payload)Pinia (统一用 action,无歧义)
模块化创建模块,在主 store 中注册创建独立 store,直接引入使用Pinia (更灵活,无注册负担)
组件中使用mapState, mapActions 辅助函数直接调用 useStore() 函数Pinia (与 Composition API 结合更紧密)
TS 体验需要大量手动定义类型完全自动的类型推断Pinia (压倒性优势)

结论:
从代码层面可以清晰地看到,Pinia 的语法更加现代、简洁和直观。它消除了 Vuex 中一些令人困惑的概念(如 Mutations),提供了卓越的 TypeScript 开发体验,并且与 Vue 3 的 Composition API 哲学完美契合。对于新项目,Pinia 是毫无疑问的更优选择。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/96871.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/96871.shtml
英文地址,请注明出处:http://en.pswp.cn/diannao/96871.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

几种方式实现文件自动上传到服务器共享文件夹

文章目录一、方案核心逻辑二、详细实现步骤&#xff08;以Windows系统为例&#xff09;1. 确认服务器共享文件夹的“访问权限”&#xff08;前提&#xff09;2. 选择“传输触发方式”&#xff08;按需求选实时/周期&#xff09;&#xff08;1&#xff09;周期传输&#xff08;如…

Milvus介绍及多模态检索实践

1、核心组件 1.1 Collection (集合) 可以用一个图书馆的比喻来理解 Collection&#xff1a; Collection (集合): 相当于一个图书馆&#xff0c;是所有数据的顶层容器。一个 Collection 可以包含多个 Partition&#xff0c;每个 Partition 可以包含多个 Entity。 Partition (分区…

第二十三天-LCD液晶显示实验

一、LCD结构体定义LCD为LCD_TypeDef类型的指针&#xff0c;指向0x6C000000的地址空间&#xff08;bank1分区4的地址范围&#xff09;。为什么需要并上0x000007FE呢&#xff1f;因为虽然驱动SRAM的时序和16位8080接口时序&#xff08;驱动LCD时序&#xff09;很像&#xff0c;但…

SQL性能调优

MySQL出现性能差的原因有哪些? 可能是 SOL查询使用了全表扫描&#xff0c;也可能是查询语句过于复杂&#xff0c;如多表 IOIN 或嵌套子查询。 也有可能是单表数据量过大。 通常情况下&#xff0c;添加索引就能解决大部分性能问题。对于一些热点数据&#xff0c;还可以通过增加…

dapo:开源大规模llm强化学习系统的突破与实现

本文由「大千AI助手」原创发布&#xff0c;专注用真话讲AI&#xff0c;回归技术本质。拒绝神话或妖魔化。搜索「大千AI助手」关注我&#xff0c;一起撕掉过度包装&#xff0c;学习真实的AI技术&#xff01; ✨ 1. dapo概述&#xff1a;开源llm强化学习系统的重要突破 dapo&…

【车载开发系列】ParaSoft集成测试环境配置(五)

【车载开发系列】ParaSoft集成测试环境配置(五) 【车载开发系列】ParaSoft集成测试环境配置(五) 【车载开发系列】ParaSoft集成测试环境配置(五) 一. 剥离硬件环境的设置 二. 灵活使用编译开关 三. 导入修改后的bdf文件 四. 自动生成底层桩函数 五. 开始跑集成测试用例 六…

大模型(一)什么是 MCP?如何使用 Charry Studio 集成 MCP?

目录一、什么是 MCP&#xff1f;1.1 &#x1f914; 开始之前的思考1.2 MCP 的定义1.3 MCP 结构二、MCP 的使用2.1 uv 的安装2.2 MCP 广场2.3 MCP 的配置2.4 MCP 的依赖安装2.5 Charry Studio2.6 测试结果背景&#xff1a; MCP 这个概念大概是 2025 年上半年火起来的&#xff0c…

源码导航页

一、Python捕捉动作发送到Unity驱动模型跟着动&#xff08;获取源码&#xff09; 二、AI输入法源码&#xff08;获取源码&#xff09; 三、Java企业级后台管理系统-登录授权角色菜单&#xff08;获取源码&#xff09; 四、Jetson实现纯视觉导航&#xff08;获取源码&#xff09…

HTTP/2 性能提升的核心原因

一、协议架构优化‌‌二进制分帧&#xff08;Binary Framing&#xff09;‌HTTP/2 将传统文本格式的报文&#xff08;如请求头、数据体&#xff09;拆分为独立的二进制帧&#xff08;Frame&#xff09;&#xff0c;每个帧包含流标识符&#xff08;Stream ID&#xff09;&#x…

vulnhub-billu_b0x靶机渗透

一、靶场详情 Billu_b0x 是 Vulnhub 上的经典中等难度靶机&#xff0c;主要考察从信息收集到提权的完整渗透流程&#xff1a;先通过端口和目录扫描发现网站入口&#xff0c;利用 SQL 注入或文件包含进入后台并上传 WebShell&#xff0c;再通过反弹 Shell 获取低权限用户&#…

C# 相机内存复用(减少图像采集耗时)以及行数复用

背景我们在做图像处理时&#xff0c;都会对一些相机的SDK进行开发完成图像采集的操作&#xff0c;为后续图像处理做准备。本文主要的目的是降低图像采集的耗时&#xff0c;应用在一些高速检测的场景下。利用循环队列内存复用的方式&#xff0c;去掉或者减少新建内存的时间。线扫…

MTK Linux DRM分析(十三)- Mediatek KMS实现mtk_drm_drv.c(Part.1)

一、简介 MediaTek (MTK) 的DRM驱动(基于mtk_drm_drv.c)是为MediaTek SoC(如MT6985、MT6895等)设计的显示子系统(Display Subsystem)驱动程序。它实现了Linux DRM/KMS框架,支持多CRTC、多平面(plane)、连接器(connector)和编码器(encoder)的显示管道。驱动处理硬…

Wireshark笔记-DHCP流程与数据包解析

背景DHCP从大学上网络课时就开始知道了&#xff0c;当时只知道&#xff0c;能让计算机上网&#xff0c;要不就静态配IP&#xff0c;要不就DHCP获取&#xff0c;就能上网。2021年时&#xff0c;毕业好几年了&#xff0c;想学习下网络知识&#xff0c;就准备考一个软考网工。按要…

Coze用户账号设置修改用户头像-前端源码

概述 Coze Studio的用户头像修改功能是用户账号设置中的重要组成部分&#xff0c;允许用户上传和更新个人头像。本文将深入分析该功能的前端实现&#xff0c;包括组件架构、文件上传处理、API设计和用户体验优化等方面。 技术架构 整体架构设计 Coze Studio采用现代化的前端架构…

新手Github提交PR(Pull requests)详细教程

一、什么是Pull requests&#xff1f; Pull Requests&#xff08;PR&#xff09;是代码协作平台&#xff08;如 GitHub、GitLab 等&#xff09;中的一种功能&#xff0c;用于提议将某分支的代码变更合并到另一个分支&#xff08;通常是主分支&#xff09;。它允许开发者在合并…

本地通过跳板机连接无公网IP的内网服务器

本地环境&#xff1a;SSH client 堡垒机&#xff1a;有公网IP&#xff0c;有连接内网服务器的秘钥 SSH配置&#xff1a; Host jmsHostName [堡垒机的公网IP]Port 22User rootIdentityFile ~/.ssh/id_rsaHost appHostName 10.0.0.14Port 22User rootIdentityFile ~/.ssh/svc-p…

B树,B+树,B*树

下面我们来详细讲解一下 B树、B树、B*树 这三种非常重要的多路平衡查找树。它们在数据库和文件系统中有着极其广泛的应用。一、为什么需要这些树结构&#xff1f;在开始之前&#xff0c;我们先思考一个问题&#xff1a;为什么已经有了二叉搜索树&#xff08;BST&#xff09;、A…

汽车零部件工厂ESOP系统工业一体机如何选型

在汽车零部件工厂的生产管理中&#xff0c;ESOP 系统发挥着至关重要的作用。而工业一体机作为 ESOP 系统的关键硬件支撑&#xff0c;其选型的合理性直接关系到生产效率的提升、生产过程的精准控制以及生产数据的可靠采集与分析。因此&#xff0c;为汽车零部件工厂选择一款适合的…

​维基框架 (Wiki Framework) 1.1.0 版本发布​ 提供多模型AI辅助开发

介绍 多模型AI辅助开发​ 维基框架1.1.0集成了主流AI引擎的统一接口&#xff0c;支持开发者按需调用不同模型的优势能力&#xff1a; ​DeepSeek​&#xff1a;专注代码生成与重构&#xff0c;擅长复杂业务逻辑实现 ​ChatGPT​&#xff1a;多模态推理能力&#xff0c;适用于…

LabVIEW调用MATLAB 的分形生成

LabVIEW 调用 MATLAB&#xff0c;可借前者可视化流程与硬件交互优势&#xff0c;结合后者强数值计算、算法能力&#xff0c;复用成熟算法提速开发&#xff0c;还能灵活改代码。但需匹配版本、装运行环境&#xff0c;数据传递有性能损耗&#xff0c;脚本出错需跨软件调试。​优点…