Vuex 4 / Pinia 简介与选择
状态管理是构建复杂 Vue 3 应用的核心需求,尤其在多组件共享数据时。Vuex 4 和 Pinia 是 Vue 生态中两种主流的状态管理工具:Vuex 4 是 Vuex 的 Vue 3 版本,延续了其成熟的设计;而 Pinia 作为新兴方案,提供了更简洁、更现代的 API。本节将介绍这两者的基本概念、特点,并对比它们的优劣,帮助你在项目中做出明智选择。
Vuex 4 简介
Vuex 是 Vue.js 的官方状态管理库,Vuex 4 是其适配 Vue 3 的版本,保持了与 Vue 2 版本的核心理念。
基本概念
- State:单一的状态树,存储所有共享数据。
- Getters:计算属性,基于 State 派生数据。
- Mutations:同步修改 State 的唯一方式。
- Actions:处理异步操作,提交 Mutations。
安装与使用
npm install vuex@next
示例:计数器
// src/store/index.js
import { createStore } from 'vuex';
export default createStore({
state: {
count: 0
},
getters: {
double(state) {
return state.count * 2;
}
},
mutations: {
increment(state) {
state.count++;
}
},
actions: {
asyncIncrement({ commit }) {
setTimeout(() => commit('increment'), 1000);
}
}
});
// main.js
import { createApp } from 'vue';
import App from './App.vue';
import store from './store';
const app = createApp(App);
app.use(store);
app.mount('#app');
<!-- App.vue -->
<template>
<div>
<p>计数:{{ count }}</p>
<p>双倍:{{ double }}</p>
<button @click="increment">同步增加</button>
<button @click="asyncIncrement">异步增加</button>
</div>
</template>
<script>
import { useStore } from 'vuex';
import { computed } from 'vue';
export default {
setup() {
const store = useStore();
const count = computed(() => store.state.count);
const double = computed(() => store.getters.double);
const increment = () => store.commit('increment');
const asyncIncrement = () => store.dispatch('asyncIncrement');
return { count, double, increment, asyncIncrement };
}
};
</script>
- 效果:点击按钮同步或异步增加计数。
特点
- 成熟稳定:Vuex 在 Vue 2 时代已被广泛使用。
- 严格模式:支持严格模式,确保 State 只通过 Mutations 修改。
- 模块化:支持模块分割大型状态。
Pinia 简介
Pinia 是 Vue 3 的下一代状态管理库,由 Vue 核心团队成员开发,旨在取代 Vuex。
基本概念
- Store:独立的状态容器,每个 Store 是一个响应式对象。
- State:使用
ref或reactive定义。 - Getters:通过
computed定义派生状态。 - Actions:普通函数,支持同步和异步操作。
安装与使用
npm install pinia
示例:计数器
// src/stores/counter.js
import { defineStore } from 'pinia';
import { ref, computed } from 'vue';
export const useCounterStore = defineStore('counter', () => {
const count = ref(0);
const double = computed(() => count.value * 2);
const increment = () => {
count.value++;
};
const asyncIncrement = () => {
setTimeout(() => count.value++, 1000);
};
return { count, double, increment, asyncIncrement };
});
// main.js
import { createApp } from 'vue';
import { createPinia } from 'pinia';
import App from './App.vue';
const app = createApp(App);
app.use(createPinia());
app.mount('#app');
<!-- App.vue -->
<template>
<div>
<p>计数:{{ count }}</p>
<p>双倍:{{ double }}</p>
<button @click="increment">同步增加</button>
<button @click="asyncIncrement">异步增加</button>
</div>
</template>
<script>
import { useCounterStore } from '@/stores/counter';
export default {
setup() {
const store = useCounterStore();
return {
count: store.count,
double: store.double,
increment: store.increment,
asyncIncrement: store.asyncIncrement
};
}
};
</script>
- 效果:与 Vuex 示例相同,但 API 更简洁。
特点
- 轻量简洁:无 Mutations,直接修改状态。
- Composition API:与 Vue 3 的函数式风格一致。
- TypeScript 支持:原生支持类型推导。
Vuex 4 vs Pinia 对比
| 特性 | Vuex 4 | Pinia |
|---|---|---|
| API 风格 | 对象式(Mutations/Actions) | 函数式(无 Mutations) |
| 状态修改 | 需通过 Mutations | 直接修改 |
| 学习曲线 | 较陡峭 | 简单直观 |
| TypeScript | 需要额外配置 | 开箱即用 |
| 体积 | 稍大(~20KB) | 更轻(~1KB) |
| 模块化 | 支持模块分割 | 每个 Store 独立 |
| 生态兼容性 | 与 Vue 2 项目兼容 | 专为 Vue 3 设计 |
Vuex 4 优点
- 成熟生态:文档完善,社区资源丰富。
- 严格控制:Mutations 提供明确的状态变更日志。
- 迁移友好:适合从 Vue 2 升级的项目。
Pinia 优点
- 简洁高效:减少样板代码,开发体验更佳。
- 现代设计:与 Composition API 无缝集成。
- 轻量灵活:无需区分同步/异步操作。
如何选择?
选择 Vuex 4
- 现有项目迁移:如果你从 Vue 2 的 Vuex 升级到 Vue 3,Vuex 4 可保持代码结构一致。
- 严格需求:需要严格的状态管理流程(如金融类应用)。
- 团队熟悉度:团队已熟悉 Vuex 工作流。
选择 Pinia
- 新项目:从零开始的 Vue 3 项目,推荐 Pinia。
- 现代开发:使用 Composition API 和 TypeScript。
- 轻量需求:追求更小的包体积和简洁代码。
建议
- 默认选择 Pinia:Vue 核心团队已将 Pinia 作为 Vue 3 的推荐状态管理方案,未来支持更强。
- 混合使用:小型项目甚至可直接用
reactive或ref,无需额外库。
综合示例:简单对比
Vuex 4
// store/index.js
import { createStore } from 'vuex';
export default createStore({
state: { user: '' },
mutations: {
setUser(state, name) { state.user = name; }
},
actions: {
updateUser({ commit }, name) { commit('setUser', name); }
}
});
<template>
<input v-model="user" @input="updateUser" />
</template>
<script>
import { useStore } from 'vuex';
import { computed } from 'vue';
export default {
setup() {
const store = useStore();
const user = computed({
get: () => store.state.user,
set: (value) => store.dispatch('updateUser', value)
});
const updateUser = (e) => store.dispatch('updateUser', e.target.value);
return { user, updateUser };
}
};
</script>
Pinia
// stores/user.js
import { defineStore } from 'pinia';
import { ref } from 'vue';
export const useUserStore = defineStore('user', () => {
const user = ref('');
const setUser = (name) => { user.value = name; };
return { user, setUser };
});
<template>
<input v-model="user" />
</template>
<script>
import { useUserStore } from '@/stores/user';
export default {
setup() {
const store = useUserStore();
return { user: store.user };
}
};
</script>
- 对比:Pinia 代码更少,直接绑定
v-model。
总结
Vuex 4 和 Pinia 各有千秋:Vuex 4 成熟稳定,适合迁移和严格场景;Pinia 轻量现代,是 Vue 3 的未来趋势。新项目推荐 Pinia,已有 Vuex 基础的项目可继续使用 Vuex 4。理解两者的差异后,你可以根据需求选择合适的工具。下一节将深入 Pinia 的使用,带你实践其强大功能!
