Pinia 凭什么把 Vuex 拍在沙滩上?一场关于“极简主义”的革命

45 阅读4分钟

哈喽兄弟们,我是大布布将军!👋

上一期咱们聊了 Composition API 是如何把 Mixin 送进历史博物馆的。评论区就有小伙伴坐不住了:“将军,逻辑复用是爽了,那状态管理呢?我看着手里的 Vuex 4 代码,满屏的 mutationsactionsmodules,还有那个让 TypeScript 抓狂的类型推导,我是不是该换个活法了?”

嘿,你问到点子上了!

如果说 Vuex 是一个等级森严、办事流程繁琐的老牌国企(改个数据还得层层审批),那 Pinia 就是一个扁平化管理、效率至上的互联网大厂(想改?直接改,别废话)。

今天,咱们就来扒一扒,这颗“小菠萝”(Pinia)到底凭什么篡位成功,成为了 Vue 3 官方推荐的“御用”状态管理库。

一、Vuex 的“劝退”时刻:你还在写 mutations 吗?

回想一下,在 Vuex 时代,我们想把一个计数器 count 加 1,需要经历什么流程?

  1. State: 定义 count
  2. Mutation: 定义一个 INCREMENT 方法(因为 Vuex 规定,只有 Mutation 能改 State,这叫“同步事务”)。
  3. Action: 如果是异步的,还得定义一个 Action,然后 commit 那个 Mutation。
  4. Component: 在组件里 dispatch Action。

我就想加个 1 而已啊! 这流程走下来,感觉像是在填报销单,还得找三个领导签字。

Pinia 的回答:删繁就简

Pinia 也就是看不过去这一点,直接把 mutations 砍了。是的,你没听错,砍了!

在 Pinia 里,Action 既可以处理同步,也可以处理异步。想改数据?在 Action 里直接 this.count++,或者在组件里直接改,没人管你。

二、代码大PK:没有对比就没有伤害

光说不练假把式,咱们直接上代码,看看实现同一个“计数器”功能,两者差多少。

选手 A:Vuex 4(繁琐的老大哥)

import { createStore } from 'vuex'

export default createStore({
  state: {
    count: 0
  },
  // 必须要有 mutations 才能改 state
  mutations: {
    INCREMENT(state) {
      state.count++
    }
  },
  // 异步操作或者复杂逻辑放这里
  actions: {
    increment({ commit }) {
      commit('INCREMENT') // !!! 这行代码我写了一万遍,真的累了
    }
  },
  getters: {
    doubleCount: (state) => state.count * 2
  }
})

选手 B:Pinia(清爽的小菠萝)

import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', {
  // state 必须是箭头函数(为了服务端渲染 SSR 安全)
  state: () => ({ 
    count: 0 
  }),
  // actions 直接干活,没有 mutations 中间商赚差价
  actions: {
    increment() {
      this.count++ // 👈 直接改!爽!
    }
  },
  getters: {
    doubleCount: (state) => state.count * 2
  }
})

或者,你还可以用更激进的 Setup Store 写法(配合 Composition API,简直起飞):

  const count = ref(0)
  const doubleCount = computed(() => count.value * 2)
  
  function increment() {
    count.value++
  }

  return { count, doubleCount, increment }
})

看到区别了吗?没有 mutations,没有 commit,没有魔法字符串。 代码量直接减半,逻辑清晰度翻倍。

三、TypeScript 支持:Vuex 的噩梦 vs Pinia 的天堂

如果你在 Vuex 里用过 TypeScript,你一定经历过绝望。

为了让 this.$store.state 有类型提示,你需要写一堆 interface,甚至还要搞什么 ModuleTree,还得自己封装 useStore... 也就是俗称的“TS 体操”。写完配置,头发都掉了一把。

Pinia 呢?

它天生就是为了 TS 设计的。上面的 Pinia 代码写完,你在组件里调用:

counter. // 👈 这里一敲点,IDE 瞬间把 count, increment 全提示出来了

自动推导,零配置。 这种丝滑的感觉,就像夏天喝了一口冰镇可乐,通透!

四、架构之争:树形 vs 扁平化

Vuex 是单棵大树: 所有的模块都要挂载到一个 root store 下面,形成一个巨大的树形结构。 访问深层数据时:state.user.permissions.admin.level... 如果要做代码分割(Code Splitting),那简直是灾难。

Pinia 是模块化积木: 没有 root store!每个 Store 都是独立的。 你需要 UserStore?引入它。 你需要 CartStore?引入它。 它们之间互相引用也很简单。这不仅让代码逻辑解耦,还天然支持代码分割按需加载,打包体积都变小了。

总结:这是时代的必然

Pinia 其实最初就是作为 Vuex 5 的实验性提案出现的,结果做着做着发现:“哎?这玩意儿比 Vuex 好用太多了!” 于是 Vue 官方直接把它扶正了。

Pinia 赢在哪?

  1. 极简: 抛弃 mutations,API 更符合直觉。
  2. TS 亲和: 类型推导极其强大,不用练“体操”。
  3. 轻量: 体积极小(约 1KB),且支持模块化打包。

所以,兄弟们,如果你还在犹豫要不要在 Vue 3 项目里用 Pinia,别犹豫了,上车吧! 把 Vuex 留在记忆里,把 Pinia 写进代码里。


互动时间: 你在从 Vuex 迁移到 Pinia 的过程中,有没有遇到什么“真香”时刻或者“坑”?或者你还在坚持用 Vuex?欢迎评论区对线!

下期预告: 既然 Vue 3 和 Pinia 都这么快了,那构建工具岂能拉胯?Vite 到底施了什么魔法,能比 Webpack 快那么多?是不是有了 Vite,Webpack 就要凉凉了?咱们下期接着聊!

lg_90841_1619336946_60851ef204362.png