使用Pinia集中管理数据
在Vue3中多个组件共享数据使用Pinia🍍,不再支持VueX。相比VueX,Pinia的优势:
- 完整的ts支持
- 足够轻量,压缩后的体积只有1kb左右;
- 去除mutations,只有state, getters,actions;
- actions支持同步和异步;
- 代码扁平化没有模块嵌套,只有store的概念,store之间可以自由使用,每一个store都是独立的
- 无需手动添加store, store一旦创建便会自动添加
- 支持Vue3和Vue2
- 支持Composition API
- 支持插件扩展 Pinia 功能
1.安装Pinia
sh
npm i pinia
2.创建store文件夹,创建index.ts文件
ts
// 1. 引入pinia
import { createPinia } from "pinia"
import { createPersistedState } from 'pinia-plugin-persistedstate'
// 2. 创建pinia
const pinia = createPinia()
pinia.use(createPersistedState({
auto: true,
storage: sessionStorage
}))
export default pinia
3. 在main.ts中配置
ts
import { createApp } from 'vue'
import App from './App.vue'
import router from "./router"
import pinia from "./store"
const app = createApp(App)
// 3. 安装pinia
app.use(pinia)
app.use(router)
app.mount('#app')
4. 在需要使用的组件编写代码
vue
<template>
<div style="width: 256px">
<a-menu
v-model:openKeys="menuState.openKeys"
v-model:selectedKeys="menuState.selectedKeys"
mode="inline"
theme="dark"
:inline-collapsed="menuState.collapsed"
:items="items">
</a-menu>
</div>
</template>
<script lang="ts" setup>
import { watch } from 'vue'
import { useMenuStateStore, useMenuDataStore } from "../store/menu"
const menuState = useMenuStateStore()
// 获取数据items有两种方式:
// 1. 从$state中获取 const items = useMenuDataStore().$state.items
// 2. 直接获取 const items = useMenuDataStore().items
// 如果运用对象解构:items将脱离state管理,下面这行代码是错误的,
// 如需读取方便请参考下一节storeToRefs
const { items } = useMenuDataStore()
watch(
() => menuState.openKeys,
(_val, oldVal) => {
menuState.preOpenKeys = oldVal
},
)
</script>
ts
import { defineStore } from "pinia"
// 菜单数据
export const useMenuDataStore = defineStore('menuData', {
// 真正存储数据的地方
state() {
return {
items: [
{
key: '1',
label: 'dashboard',
title: '工作台',
}
]
}
}
})
运行控制台可以看到一个菠萝🥭:
5. 修改数据的三种方式
5.1 直接修改
相比Vuex,Pinia支持直接修改
ts
countStore.sum = 666
5.2 批量修改
ts
countStore.$patch({
sum: 999,
school: '山东南翔'
})
5.3 借助action修改
ts
import { defineStore } from "pinia"
export const useCountStore = defineStore('count', {
state(){
return {
sum:100
}
}
// actions中存放方法,用于响应组件中的"动作"
actions:{
// 加法逻辑
increment(value:number){
if(this.sum<10){
// 操作countStore中的sum
this.sum += sum
}
}
}
})
6. storeToRefs
模版里面每次读取store数据不是很方便,使用对象解构可以方便读取,但是对属性需要增加响应式,如果使用toRefs,那么将store里面所有的属性都变成响应式: 我们只需要state中的数据变成响应式,推荐使用pinia提供的
storeToRefs
函数
ts
import { watch } from 'vue'
import { useMenuStateStore, useMenuDataStore } from "../store/menu"
import { useCurrentUserDataStore } from "../store/user"
import { storeToRefs } from "pinia"
const {openKeys, selectedKeys, preOpenKeys } = storeToRefs(useMenuStateStore())
const { items } = storeToRefs(useMenuDataStore())
const currentUserData = useCurrentUserDataStore()
import axios from 'axios'
const {data:menuData } = await axios.get(`api/getMenus?userId=${currentUserData.userId}`)
console.log(menuData)
// 刷新全局缓存
menuData.forEach((ele: { key: string; label: string; title: string; }) => {
items.push(ele)
});
watch(
() => openKeys,
(_val, oldVal) => {
preOpenKeys = oldVal
},
)
7. 使用getters
- 概念:当state中的数据,需要经过处理后再使用时,可以使用getters配置
- 配置getters
ts
import { defineStore } from "pinia"
export const useCountStore = defineStore('count', {
state(){
return {
sum:100,
school: '南翔'
}
},
getters:{
bigSum(state){
return state.sum*10
},
updateSchool():string{
return this.school = '山东南翔'
}
}
8 使用$subscribe监测数据
通过store的$subscribe()方法侦听state及其变化
vue
<template>
<div style="width: 256px">
<a-menu
v-model:openKeys="openKeys"
v-model:selectedKeys="selectedKeys"
mode="inline"
theme="dark"
:inline-collapsed="collapsed"
:items="items">
</a-menu>
</div>
</template>
<script lang="ts" setup>
import { watch } from 'vue'
import { useMenuStateStore, useMenuDataStore } from "../store/menu"
const menuState = useMenuStateStore()
const {openKeys, selectedKeys, preOpenKeys } = storeToRefs(useMenuStateStore())
const { items } = storeToRefs(useMenuDataStore())
watch(
() => openKeys,
(_val, oldVal) => {
preOpenKeys = oldVal
},
)
menuState.$subscribe((mutate, state)=>{
console.log('menuState里面保存的数据发生变化')
})
</script>