Pinia是什么
Pinia是vue团队推荐的下一代状态管理方案,相比之前的vuex方案,Pinia具有以下特点:
- 配合vue3 Componsition API写法,更可靠的TypeScript 类型推断支持
- Pinia 没有 Mutations,可以直接修改state数据,Actions 支持同步和异步
- 提供扁平结构,没有模块的嵌套结构等
安装依赖
npm i pinia -S
接着src目录下创建stores文件夹(注意:这里用复数形式命名以强调pinia的多状态实例的特性,也就是上面提到的特点3)
初始化工作
创建index.ts文件:
stores文件夹下新建index.ts:
import { createPinia } from 'pinia'
const pinia = createPinia()
export default pinia
在main.ts中引用:
import { createSSRApp } from 'vue'
import App from './App.vue'
import pinia from './store'
export function createApp() {
const app = createSSRApp(App)
app.use(pinia)
return {
app,
}
}
以上就完成了初始化工作,下面我们定义一个user模块说明如何使用
定义user模块
在stores目录下新建user文件夹,在其目录下我们新建两个文件:index.ts和types.ts(管理数据结构)
index.ts:
import { defineStore } from 'pinia'
import { RootState } from './types'
export const useUserStore = defineStore('user', {
state: (): RootState => ({
userInfo: {},
token: '',
}),
getters: {
// 示例返回大写字符
capName(state) {
return state.userInfo.name.toUpperCase()
},
},
actions: {
async setUserInfo() {
// 这里可以发起请求
const userInfo = await getUserInfo()
this.userInfo = userInfo
},
},
})
- defineStore方法第一个参数“user”是模块的名称,值必须是唯一的(多个模块不能重名)
- state:箭头函数,返回一个对象数据
- getters:可以理解为计算属性,对state中的数据做进一步计算处理
- actions:封装业务逻辑,同步/异步修改state数据
值得一提的是,对于store模块命名写法,有个约定俗成的写法:使用“use”+ 功能模块名称,如上面的useUserStore
页面中使用
<template>
<view>{userStore.userInfo.name}</view>
</template>
<script setup lang="ts">
import { useUserStore } from '@/stores/user'
const userStore = useUserStore()
console.log(userStore.userInfo)
</script>
解构state
如果要使用解构写法获取值,而又不丢失响应式,我们需要用到storeToRefs方法
const { userInfo } = storeToRefs(userStore)
userInfo.value.name = 'username'
修改state
- 直接修改:userStore.userInfo = {}
- $patch批量修改(性能更好):
// $patch有两种写法
// 传入对象:适合同时修改多个不复杂的数据
store.$patch({
userInfo: {},
token: '',
})
// 传入函数写法:上面传入对象写法在遇到复杂数据时,成本很高
//(例如,从数组中推送、删除、拼接元素)都需要创建一个新集合,这时就可以传入一个函数
cartStore.$patch((state) => {
state.items.push({ name: 'shoes', quantity: 1 })
state.hasChanged = true
})
- $reset恢复初始值:例如我们在state中定义一个userInfo初始值
userInfo: {
name: '默认用户名',
avatar: '默认用户头像'
}
假设用户登录后我们修改了上面的用户信息,退出登录时,我们可以直接调用userStore.$reset()恢复初始值。不过要注意的是,它恢复的是整个state值,并不能只恢复state下面的单个值。对此,我们可以将有恢复初始值的需求的变量,用一个变量存储然后在需要恢复时,可以在action中定义一个方法重新赋值即可。
监听状态
如果你需要监听状态做一些处理,例如将数据持久化到本地,可以使用$subscribe()方法。
userStore.$subscribe((mutations, state) => {
uni.setStorageSync('userInfo', state.userInfo)
})
数据持久化插件:pinia-plugin-persistedstate
在只需要本地存储一小部分字段时,可以通过上面监听状态钩子简易实现。但如果需要存储大量数据字段,则可以使用与之搭配的插件:pinia-plugin-persistedstate
安装
npm i pinia-plugin-persistedstate
修改stores/index.ts
import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)
export default pinia
user模块
export const useUserStore = defineStore('user', {
state: (): RootState => ({
userInfo: {
id: null,
name: '',
},
token: '',
userName: '',
}),
persist: {
key: 'store-key', // 本地存储key
storage: {
setItem: uni.setStorageSync,
getItem: uni.getStorageSync,
},
},
actions: {
setName(name: string) {
this.userName = name
},
},
})
打开微信开发者工具可以看到:
可以看到上面存储的是整个user模块的state数据,如果只需要存储state下的某些字段,可以这么写:
persist: {
key: 'store-key',
paths: ['userInfo.name'],
storage: {
setItem: uni.setStorageSync,
getItem: uni.getStorageSync,
},
}
微信开发工具中显示如下:
总结
至此,已经完成了pinia状态管理使用及配合pinia-plugin-persistedstate插件实现数据本地存储,接下来请移步《网络请求封装篇》。
- 我正在参与掘金技术社区创作者签约计划招募活动,点击链接报名投稿。