1、Pinia入门:Pinia是什么、为什么选择Pinia、Pinia与Vuex的对比、Pinia的核心概念
Pinia是什么?一个更懂你的状态管理库
说实话,我第一次接触Pinia的时候,心里想的是:「又来一个新玩具?」
但用了一个下午之后,我彻底改观了。Pinia是Vue生态里最新的状态管理方案,由Vue核心团队成员Eduardo San Martin Morote开发。你可以把它理解成Vuex的「精神继承者」——但更轻、更快、更符合直觉。
我个人的习惯是,每次新项目启动前,都会先看看社区里最新的最佳实践。2022年以后,我几乎所有的Vue3项目都换成了Pinia。为什么?因为它的API设计实在太舒服了。
一句话总结:Pinia是一个基于Composition API的状态管理库,它让你用写普通JavaScript的方式管理全局状态。
为什么选择Pinia?三个让我「回不去」的理由
我在项目中遇到过不少状态管理的坑。Vuex的Mutation让我觉得啰嗦,Module的嵌套让人头晕。Pinia的出现,说白了就是解决了这些痛点。
1. 完整的TypeScript支持
你想想看,以前用Vuex的时候,要配TypeScript得写多少类型声明?光是一个模块的State、Getter、Mutation、Action,就得定义四套类型。Pinia不一样,它天然就是类型安全的。你写一个store,TypeScript自动推断出所有类型。
// Vuex 时代:手动定义类型
interface State {
count: number
}
const store = new Vuex.Store<State>({...})
// Pinia 时代:自动推断
export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
return { count }
})
// count 自动就是 Ref<number> 类型
2. 告别Mutation,拥抱Action
我记得刚学Vuex的时候,最困惑的就是:为什么改个数据还要分Mutation和Action?一个同步一个异步,但实际开发中经常搞混。Pinia直接砍掉了Mutation,所有状态变更都在Action里完成。
我的建议:如果你是从Vuex迁移过来的,把Mutation里的逻辑直接搬到Action里就行。少了一层心智负担,代码反而更清晰。
3. 模块化不再嵌套
Vuex的Module是嵌套的,你创建一个user模块,访问的时候要写 store.state.user.info.name。Pinia是扁平化的,每个store都是独立的,直接 useUserStore().info.name。嗯,这里要注意,扁平化带来的好处是:代码拆分更自由,你甚至可以按功能拆成多个文件。
Pinia与Vuex的对比:一张表看懂
| 对比维度 | Vuex 4.x | Pinia |
|---|---|---|
| API风格 | Options API(类似Vue2组件) | Composition API(类似Vue3 setup) |
| TypeScript支持 | 需要手动声明类型 | 天然类型安全,自动推断 |
| Mutation | 有,必须通过Mutation修改状态 | 无,直接在Action中修改 |
| 模块化 | 嵌套Module,命名空间需手动开启 | 扁平化Store,每个store独立 |
| DevTools支持 | 支持,但调试体验一般 | 支持,时间旅行、状态快照更流畅 |
| 代码体积 | 约9KB(gzip后) | 约1KB(gzip后) |
| 学习成本 | 需要理解Mutation、Action、Module等概念 | 几乎零成本,会写Composition API就会用 |
为什么会这样?说白了,Pinia是站在Vuex的肩膀上重新设计的。它保留了Vuex的核心思想(集中式状态管理),但去掉了那些被实践证明「不那么必要」的约束。
Pinia的核心概念:三个词搞定
Pinia的核心概念只有三个:State、Getter、Action。你想想看,这不就是Vue组件里的data、computed、methods吗?没错,Pinia就是把组件级别的状态管理,提升到了全局级别。
State:数据从哪里来?
State就是存储数据的地方。在Pinia里,它就是一个函数,返回一个对象。我个人习惯用setup语法(也就是函数式写法),因为更灵活。
export const useUserStore = defineStore('user', () => {
// State
const name = ref('张三')
const age = ref(25)
const hobbies = ref(['编程', '读书'])
// 返回
return { name, age, hobbies }
})
Getter:数据怎么加工?
Getter相当于计算属性。它依赖State,并且有缓存。我在项目中经常用Getter来处理需要派生的数据,比如格式化日期、过滤列表等。
export const useUserStore = defineStore('user', () => {
const name = ref('张三')
const age = ref(25)
// Getter
const userInfo = computed(() => `${name.value},${age.value}岁`)
const isAdult = computed(() => age.value >= 18)
return { name, age, userInfo, isAdult }
})
避坑指南:我曾经在Getter里直接修改State,结果导致UI更新异常。记住,Getter是只读的,永远不要在里面做赋值操作。想修改数据?去Action里做。
Action:数据怎么改?
Action是Pinia里最核心的部分。它既可以同步修改State,也可以处理异步逻辑。你不需要像Vuex那样区分同步和异步,全部写在Action里就行。
export const useUserStore = defineStore('user', () => {
const name = ref('张三')
const age = ref(25)
// Action
function updateName(newName: string) {
name.value = newName
}
async function fetchUser() {
const res = await api.getUser()
name.value = res.name
age.value = res.age
}
return { name, age, updateName, fetchUser }
})
你看,Action就是一个普通的函数。同步也好,异步也罢,想怎么写就怎么写。嗯,这里要注意,Action里的 this 指向store实例,但如果你用setup语法,直接用变量就行,不需要 this。
一个小例子:从零搭建计数器
光说不练假把式。我们用一个最简单的计数器来感受一下Pinia的用法。
// stores/counter.ts
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
export const useCounterStore = defineStore('counter', () => {
// State
const count = ref(0)
// Getter
const doubleCount = computed(() => count.value * 2)
// Action
function increment() {
count.value++
}
function decrement() {
count.value--
}
function reset() {
count.value = 0
}
return { count, doubleCount, increment, decrement, reset }
})
// 在组件中使用
<script setup lang="ts">
import { useCounterStore } from '@/stores/counter'
const counter = useCounterStore()
</script>
<template>
<div>
<p>计数:{{ counter.count }}</p>
<p>双倍:{{ counter.doubleCount }}</p>
<button @click="counter.increment">+1</button>
<button @click="counter.decrement">-1</button>
<button @click="counter.reset">重置</button>
</div>
</template>
是不是很简单?你甚至可以直接在模板里修改State:counter.count++。这在Vuex里是绝对不允许的,但Pinia觉得——你是个成熟的开发者了,应该知道自己什么时候该做什么。
我的经验:虽然Pinia允许直接修改State,但我建议还是统一用Action。原因有二:一是方便调试,DevTools能记录每次变更;二是后期维护时,你能快速定位到所有修改逻辑。
总结一下
Pinia不是什么高深莫测的东西。它就是Vuex的「简化版+增强版」——去掉了Mutation和嵌套Module,加上了完整的TypeScript支持和Composition API风格。说白了,它就是让你用更少的代码,做更多的事。
下一章,我们会手把手搭建一个Pinia项目,从安装配置到第一个Store,让你真正上手。到时候你会发现,原来状态管理可以这么轻松。