Pinia 是 Vue 的专属状态管理库,是 Vuex 的一个替代品,并支持组合式 API。
Pinia 是一个 Store ,它是一个保存状态和业务逻辑的实体,保存着全局状态,有点像一个永远存在的组件,每个组件都可以读取和写入它。
Pinia 有三个概念,state, getter, action,类似于组件中的 data ,computed ,methods。
2. 使用
使用 npm install pinia 安装,安装后将实例注册到 Vue3 应用
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 
 | 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')
 
 | 
使用的最佳实践,是将它定义在一个单独文件中
| 12
 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
 
 | import { defineStore } from 'pinia'
 
 
 
 
 
 
 export const useCounterStore = defineStore('counter', {
 state: () => (
 return {
 name:"defaultName",
 count: 0
 }
 ),
 getters: {
 getCount(): number {
 return this.count;
 },
 getName(): string {
 return this.name;
 },
 double: (state) => state.count * 2,
 greeting(str: string) {
 return str + this.name;
 },
 },
 actions: {
 increment() {
 this.count++
 },
 setName(name: string) {
 this.name = name;
 },
 setCount(n: number) {
 this.count = 500 + n;
 },
 },
 })
 
 | 
1. state
state 被定义为一个返回初始状态的函数,可以在 vue 文件中引入后进行查询、修改、重置其值。
修改值有 5 种方法:
- 直接修改
- 在 $patch中通过属性修改
- 推荐:在 $patch中通过工厂函数修改
- $state中通过属性修改,但必须修改整个对象
- 通过 Pinia 中 actions修改
| 12
 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
 
 | import { useCounterStore } from './store'
 
 const Counter = useCounterStore()
 
 
 const change1 = () => {
 Counter.count++
 }
 
 const change2 = () => {
 Counter.$patch({
 count:200,
 name:"hello"
 })
 }
 
 const change3 = () => {
 Counter.$patch((state)=>{
 state.count = 300,
 state.name = "world"
 })
 }
 
 const change4 = () => {
 Counter.$state = ({
 count: 400,
 name: "hello world"
 })
 }
 
 const change5 = () => {
 Counter.setCount(100)
 }
 
 | 
2. getters
getters 完全等同于 store 的 state 的计算值,使用 this 访问整个 store 实例。
推荐使用箭头函数,并且它将接收 state 作为第一个参数。
| 12
 3
 4
 5
 6
 
 | getters: {otherGetter(state) {
 const otherStore = useOtherStore()
 return state.localData + otherStore.data
 },
 },
 
 | 
可以像访问 state 属性一样,直接访问任何 getter
| 12
 3
 4
 
 | const store = useCounterStore()
 store.count = 3
 store.doubleCount
 
 | 
3. actions
action 相当于组件中的 method,也使用 this 访问整个 store 实例,并且它们也是定义业务逻辑的完美选择。
在其中,可以使用同步和异步方法,也可以互相调用
| 12
 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
 
 | type User = {
 name: string;
 age: number;
 };
 
 const Login = (): Promise<User> => {
 return new Promise((resolve) => {
 
 setTimeout(() => {
 resolve({
 name: "小明",
 age: 18,
 });
 }, 2000);
 });
 };
 
 export const useUserStore = defineStore(Names.User, {
 state: () => {
 return {
 user: <User>{},
 name: "初始值"
 };
 },
 actions: {
 async setUser() {
 const result = await Login();
 this.user = result;
 this.setName("异步调用同步方法");
 },
 setName(name: string) {
 this.name = name;
 },
 },
 getters: {}
 });
 
 | 
4. 其他 api
- $reset: 重置为初始值
- $subscribe:- state中值变化时,会被调用
- $onAction:- actions调用时,会被调用
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 
 | const User = useUserStore()
 
 const reset = () => {
 User.$reset()
 }
 User.$subscribe((mutation, state) => {
 console.log("mutation=",mutation);
 console.log("state=",state);
 })
 
 User.$onAction(({
 name, // action 名称
 store, // store 实例,类似 `someStore`
 args, // 传递给 action 的参数数组
 after, // 在 action 返回或解决后的钩子
 onError, // action 抛出或拒绝的钩子
 }) => {
 console.log("onAction name=",name);
 console.log("onAction store=",store);
 console.log("onAction args=",args);
 console.log("onAction after=",after);
 console.log("onAction onError=",onError);
 })
 
 | 
3. 注意
1. 解构
解构后的属性值,默认不具有响应式,可以使用 pinia 提供的 api 将它转换为响应式的
| 12
 3
 4
 5
 6
 7
 8
 9
 
 | import { useCounterStore } from './store'import { storeToRefs } from 'pinia';
 
 const Counter = useCounterStore()
 const User = useUserStore()
 
 const {count, name} = Counter
 
 const {name, age} = storeToRefs(User)
 
 |