介绍

Pinia是Vue的专属状态管理库,它允许我们跨组件或页面共享状态,官方文档链接:Home | Pinia (vuejs.org)

安装

我使用的Vue.js版本是3.2.45(也就是Vue3),并且项目使用Vite4创建的,Vue3安装Pinia只需要执行下面的命令即可,Vue2则还需要安装一个插件,这里不讨论,可以去查看官方文档:安装 | Pinia (vuejs.org)

1
npm install pinia

使用

创建实例传递给应用

创建一个pinia实例(根store)并将其传递给应用

1
2
3
4
5
6
7
8
import { createApp } from 'vue'
import { createPinia } from "pinia"
import './style.css'
import App from './App.vue'

const pinia = createPinia()

createApp(App).use(pinia).mount('#app')

定义store

/src/stores目录下创建一个index.ts文件

useStore是返回值的名称,main是名字id,都可以随意命名,但是返回值的名称最好使用store的名字,同时以 use 开头且以 Store 结尾(比如 useUserStoreuseCartStoreuseProductStore)

1
2
3
4
5
import { defineStore } from "pinia"

export const useStore = defineStore('main', {

})

State

定义state

state是store的核心,用于跨组件或页面共享状态

1
2
3
4
5
6
7
8
9
import { defineStore } from "pinia"

export const useStore = defineStore('main', {
state: () => {
return {
count: 1
}
}
})

访问state

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
<script setup lang="ts">
// 引入useStore
import { useStore } from "./stores/index";
// 获得useStore的返回值
const store = useStore();
// store.count自加1
const addCount = () => {
store.count++;
};
</script>

<template>
<div>
<h1>{{ store.count }}</h1>
<button @click="addCount">+1</button>
</div>
</template>

<style scoped>
div {
text-align: center;
}
h1 {
color: red;
}
</style>

重置state

通过store.$reset()可以重置state的值

1
2
3
4
// 重置
const reset = () => {
store.$reset();
};

变更state

通过store.$patch修改state(一般用于修改多个数据),只修改一个可以直接修改

1
2
3
4
5
6
7
8
9
10
// store.$patch修改成123
const modify = (): void => {
store.$patch(state => {
state.count = 123
})
};
// 直接修改成123
const modify2 = (): void => {
store.count = 123;
};

替换state

替换和变更的区别就是,替换用于修改全部数据,而变更是修改一个或多个数据

1
2
3
4
5
6
7
// 替换
const replace = (): void => {
store.$state = {
count: 666,
name: "jack",
};
};

订阅state

通过store.$subscribe方法订阅state后,一旦state的数据发生变更,我们可以对变更后的数据进行一些操作,例如可以对数据进行持久化,不然一刷新页面数据就重置了

mutation返回值包含了操作的状态、state改变前的值、state改变后的值……

state返回值则是修改后的state的数据

上面两个返回值的名称可以随便写

1
2
3
4
5
6
// 订阅
store.$subscribe((mutation, state) => {
console.log(mutation);
console.log(state);
window.localStorage.setItem("useStoreState", JSON.stringify(state));
});

Getter

Getter完全等同于store的state的计算值,接收 state 作为第一个参数,对state的数据进行统一处理,下面的doubleCount对state.count乘以2,直接通过store.doubleCount()调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { defineStore } from "pinia"

export const useStore = defineStore('main', {
state: () => {
return {
count: 1,
name: 'tom'
}
},
getters: {
// 计算state.count * 2
doubleCount: (state) => state.count * 2
}
})

调用同一个store的getter可以使用this关键词

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import { defineStore } from "pinia"

export const useStore = defineStore('main', {
state: () => {
return {
count: 1,
name: 'tom'
}
},
getters: {
// 计算state.count * 2
doubleCount: (state) => state.count * 2,
// 调用同一个store的getter
doublePlusOne(): number {
return this.doubleCount + 1
}
}
})

Action

Action相当于组件中的method,在组件中直接通过store.increment()进行调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import { defineStore } from "pinia"

export const useStore = defineStore('main', {
state: () => {
return {
count: 1,
name: 'tom'
}
},
getters: {
// 计算state.count * 2
doubleCount: (state) => state.count * 2,
// 调用同一个store的getter
doublePlusOne(): number {
return this.doubleCount + 1
}
},
actions: {
increment() {
this.count++
}
}
})

持久化

介绍

state改变后,一旦刷新页面后就恢复默认值了,如果我们需要保留修改后的state,那么就需要将state持久化了,持久化的方法有两个:

  1. 使用pinia-plugin-persist插件,建议使用
  2. 通过订阅state将每次改变后的数据通过localStorage或者sessionStorage持久化到本地

使用插件

安装

使用下面命令安装

1
npm i pinia-plugin-persistedstate
引入

main.ts中全局引入

1
2
3
4
5
6
7
8
9
10
import { createApp } from 'vue'
import { createPinia } from "pinia"
import piniaPluginPersistedstate from "pinia-plugin-persistedstate";
import './style.css'
import App from './App.vue'

const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)

createApp(App).use(pinia).mount('#app')
使用

在要持久化的store中加上persist

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import { defineStore } from "pinia"

export const useStore = defineStore('main', {
state: () => {
return {
count: 1,
name: 'mary'
}
},
persist: {
key: 'useStore',
storage: sessionStorage,
paths: ['count', 'name']
}
})

参数说明如下:

参数 说明
key 自定义存储的key,默认是store.$id
storage 存储的类型:sessionStoragelocalStorage,默认是sessionStorage
paths 要持久化的数据,state中的字段名,默认是全部

通过订阅state

首先订阅state,然后将数据放到localStoragesessionStorage

1
2
3
4
5
6
// 订阅
store.$subscribe((mutation, state) => {
console.log(mutation);
console.log(state);
window.localStorage.setItem("useStoreState", JSON.stringify(state));
});

需要持久化哪个数据就从本地存储的state中获取它,不然就是默认值

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
import { defineStore } from "pinia"
// 获取本地存储的useStoreState,如果没有就设置默认值
const json: string = window.localStorage.getItem("useStoreState") || '{"count":1,"name":"tom"}'
// 解析
const obj: any = JSON.parse(json)

export const useStore = defineStore('main', {
state: () => {
return {
count: obj.count,
name: obj.name
}
},
getters: {
// 计算state.count * 2
doubleCount: (state) => state.count * 2,
// 调用同一个store的getter
doublePlusOne(): number {
return this.doubleCount + 1
}
},
actions: {
increment() {
this.count++
}
}
})