Pinia 是 Vue 的专属状态管理库,Vue3官网推荐使用Pinia,Pinia支持Vue2和Vue3。
Pinia 对比 vuex
- 没有了 mutations 这个概念只需要用 Action就可以定义同步和异步的方法
 - 没有了 modules Pinia里每个store是一个模块
 - 轻量化 Pinia 大小只有 1kb 左右!
 
起步
安装 pinia
1 2 3
   | yarn add pinia
  npm install pinia
   | 
Vue3使用
1 2 3 4 5 6 7 8 9
   | import { createApp } from 'vue' import { createPinia } from 'pinia' import App from './App.vue'
  const pinia = createPinia() const app = createApp(App)
  app.use(pinia) app.mount('#app')
  | 
Store
defineStore来定义Store,每个store是一个模块
1 2 3 4 5 6 7 8 9 10 11
   | import { defineStore } from 'pinia'
  const countStore = defineStore('storeId', {   state: () => {     return {       count: 0,     }   }, })
  export { countStore };
  | 
使用state
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
   | const store = countStore() // 可以通过 store 实例访问 state,直接对其进行读写 store.count++
  // 重置 state store.$reset()
  // 变更 state 除了用 store.count++ 直接改变 store,你还可以调用 $patch 方法。它允许你用一个 state 的补丁对象在同一时间更改多个属性 store.$patch({   count: store.count + 1,   age: 120 })
  // 订阅 state store.$subscribe((mutation, state) => {   // mutation.type // ‘direct’ | ‘patch object’ | ‘patch function’   // mutation.storeId // 'storeId'   console.log(mutation, state); }, { detached: true });
   | 
订阅$subscribe
- mutation.type
- direct 直接修改值
 - patch object 通过 patch 传对象方式修改
 - patch function 通过 patch 函数形式修改值
 
 - detached: true 订阅器即便在组件卸载之后仍会被保留
 
注: store.$state = { count: 24 } 不能完全替换掉 store 的 state,因为那样会破坏其响应性。要使用$patch来修改。
Getter
Getter 完全等同于 store 的 state 的计算值。可以通过 defineStore() 中的 getters 属性来定义它们。
1 2 3 4 5 6 7 8 9 10
   | const countStore = defineStore('storeId', {   state: () => {     return {       count: 0,     }   },   getters: {     doubleCount: (state) => state.count * 2,   }, })
  | 
使用和state一样。Getter也可以不依赖于state,可以使用其他 getter 来计算。
Action
Action 相当于组件中的 method。它们可以通过 defineStore() 中的 actions 属性来定义。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
   | const countStore = defineStore('storeId', {   state: () => {     return {       count: 0,     }   },   getters: {     doubleCount: (state) => state.count * 2,   },   actions: {     increment() {       this.count++     },   } })
  const store = countStore() // 直接使用actions store.increment()
  | 
Action 里面不同区分同步还是异步,比vuex更简单和使用方便。
订阅 action 通过 store.$onAction(callback, false) 来监听 action 和它们的结果。传递给它的回调函数会在 action 本身之前执行。after 表示在 promise 解决之后,允许你在 action 解决后执行一个回调函数。同样地,onError 允许你在 action 抛出错误或 reject 时执行一个回调函数。组件销毁会自动删除action 订阅器,如需保留可以传递第二个参数 true。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
   | const store = countStore() const unsubscribe = store.$onAction(   ({     name,      store,      args,      after,      onError,    }) => {           const startTime = Date.now()          console.log(`Start "${name}" with params [${args.join(', ')}].`)
                after((result) => {       console.log(         `Finished "${name}" after ${           Date.now() - startTime         }ms.\nResult: ${result}.`       )     })
           onError((error) => {       console.warn(         `Failed "${name}" after ${Date.now() - startTime}ms.\nError: ${error}.`       )     })   } )
 
  unsubscribe()
   | 
访问其他 store 的 Store、 getter、 Action
Pinia里每个store是一个模块,直接import 实例化 就可以使用其他store 的 Store、 getter、 Action。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
   | export const ageStore = defineStore("ageStore", {   state: () => {     return {       age: 18     };   },   getters: {     doubleAge: (state) => state.age * 2   },   actions: {     increment() {       this.age++;     }   } });
  // 引入 ageStore 并使用ageStore 的 Store、 getter、 Action import { ageStore } from "./age"; const countStore = defineStore("storeId", {   state: () => {     // 使用 ageStore 的 state     const age = ageStore();     return {       count: 0,       age: age.age     };   },   getters: {     doubleCount: (state) => state.count * 2   },   actions: {     increment() {       // 使用 ageStore 的 actions       const age = ageStore();       age.increment();       this.count++;     }   } });
  export { countStore };
  | 
注: 两个或更多的 store 相互使用,它们不可以通过 getters 或 actions 创建一个无限循环。它们也不可以同时在它们的 setup 函数中直接互相读取对方的 state
组合式API写法
1 2 3 4 5 6 7 8
   | export const useCounterStore = defineStore('counter', () => {   const count = ref(0)   function increment() {     count.value++   }
    return { count, increment } })
  | 
在 Setup Store 中:
- ref() 就是 state 属性
 - computed() 就是 getters
 - function() 就是 actions
demo
demo 
参考
pinia