Pinia 状态管理
前置说明
状态管理采用官方 Pinia v3.0.4 单文件版,适配 uni-app-x 蒸汽 JS 引擎,并去掉了 @vue/devtools-api。 具体位置在 uni_modules/x-pinia-s/js_sdk/pinia.js。另外提供了持久化插件 piniaPersist.ts,用 uni.setStorageSync 保存 store.$state,下次启动自动还原。
演示见 pages/store/xPiniaStore,跨页读取见 pages/store/storeChildPage。业务登录态见 store/useUserStore.uts。
安装 Pinia
import App from './App.uvue'
import { createSSRApp } from 'vue'
import Xui from "@/uni_modules/tmx-ui"
// @ts-ignore
import { createPinia } from '@/uni_modules/x-pinia-s/js_sdk/pinia'
import { createPersistPlugin } from '@/uni_modules/x-pinia-s/js_sdk/piniaPersist'
const pinia = createPinia()
export function createApp() {
// @ts-ignore
const app = createSSRApp(App)
pinia.use(createPersistPlugin({
keyPrefix: 'pinia:',
includeStores: ['counter', 'user'],
excludeStores: [],
serializer: null
}))
app.use(pinia)
app.use(Xui)
return {
app
}
}includeStores 是白名单,只有写进去的 store.$id 才会持久化。当前演示把 counter、user 加进去了。excludeStores 是黑名单,同时命中时黑名单优先。includeStores 为 null 表示全部持久化。
定义 Store
推荐 Setup 写法。defineStore 的第一个参数是唯一 id,持久化白名单按这个 id 匹配。
演示页用的是 pages/store/useInfo.uts:
import { defineStore } from '@/uni_modules/x-pinia-s/js_sdk/pinia'
export const useCounterStore = defineStore('counter', () => {
const count = ref<number>(0)
const name = ref<string>('')
const doubled = computed(() : number => count.value * 2)
const increment = () => {
count.value++
}
const setName = (n : string) => {
name.value = n
}
const reset = () => {
count.value = 0
name.value = ''
}
return {
count,
name,
doubled,
increment,
setName,
reset
}
})请求库用的登录态在 store/useUserStore.uts,id 为 user:
import { ref, computed } from 'vue'
import { defineStore } from '@/uni_modules/x-pinia-s/js_sdk/pinia'
import type { UseInfo } from '@/pages/request/interface'
export const useUserStore = defineStore('user', () => {
const token = ref<string | null>(null)
const user = ref<UseInfo>({
naicename: '',
avatar: '',
id: '',
tags: [] as string[],
level: -1
} as UseInfo)
const isLogin = computed(() : boolean => token.value != null && token.value != '')
const setLogin = (newToken : string | null, userInfo : UseInfo | null) => {
token.value = newToken
if (userInfo != null) {
user.value = userInfo!
}
}
const loginOut = () => {
token.value = null
user.value = {
naicename: '',
avatar: '',
id: '',
tags: [] as string[],
level: -1
} as UseInfo
}
return {
token,
user,
isLogin,
setLogin,
loginOut
}
})在任意 Uts 中使用
import { useUserStore } from "@/store/useUserStore.uts"
const userStore = useUserStore()
console.log(userStore.token)
console.log(userStore.isLogin)
userStore.setLogin('demo-token-888', null)在 Uvue 内使用
1.组合式模板内
store 本身是响应式的,模板里可以直接绑 store.xxx,也可以调 action。
import { useCounterStore } from "./useInfo.uts"
const store = useCounterStore()
store.increment()uts 内导入后可以在模板内使用
<x-stepper v-model="store.count"></x-stepper>
<x-text>{{store.doubled}}</x-text>
<x-button @click="store.increment()">计数叠加</x-button>
<x-input v-model="(store.name as string)"></x-input>2.跨页面解构,保持响应式
直接 const { count } = store 会丢掉响应式。跨页或要拆字段时用 storeToRefs。
import { storeToRefs } from '@/uni_modules/x-pinia-s/js_sdk/pinia'
import { useCounterStore } from "./useInfo.uts"
const store = useCounterStore()
const { count, name, doubled } = storeToRefs(store)
<x-text>count:{{count}}</x-text>
<x-text>computed: {{doubled}}</x-text>
<x-text>name: {{name}}</x-text>演示子页是 pages/store/storeChildPage,和父页共用同一个 counter store。
订阅状态变化
import { useCounterStore } from "./useInfo.uts"
const store = useCounterStore()
store.$subscribe((m, state) => {
console.log(m, state)
})持久化
挂上 createPersistPlugin 后,白名单里的 store 每次 $state 变化都会写入本地。关闭应用再打开,会还原成上次的值。
演示页改完 count / name 后关掉 App,再进 /pages/store/xPiniaStore 就能看到恢复结果。点重置只清内存,若该 store 在白名单里,下一次变化仍会写回存储。
只清存储、不影响内存状态:
import { clearPersistedState } from '@/uni_modules/x-pinia-s/js_sdk/piniaPersist'
clearPersistedState('counter', 'pinia:')Pinia 方法
如果想看完整类型,见插件目录 uni_modules/x-pinia-s/js_sdk/pinia.d.ts。
| 名称 | 说明 |
|---|---|
| createPinia | 创建 Pinia 实例,在 main.uts 里 app.use(pinia) |
| defineStore | 定义 store,支持 options 与 setup 两种写法 |
| storeToRefs | 解构 state / getters 并保持响应式 |
| mapState / mapActions / mapStores / mapWritableState | Options API 辅助函数 |
| setActivePinia / getActivePinia | 组件外或 SSR 时切换活动实例 |
| disposePinia | 销毁 Pinia 实例 |
| createPersistPlugin | 持久化插件 |
| clearPersistedState | 清除某个 store 的持久化数据 |
持久化插件参数
export type PersistSerializer = {
serialize : (state : any) => string,
deserialize : (raw : string) => any
}
export type PersistOptions = {
/** storage key 前缀,默认 pinia: */
keyPrefix : string,
/** 白名单;null 表示全部持久化 */
includeStores : string[] | null,
/** 黑名单,优先级高于 includeStores */
excludeStores : string[],
/** 自定义序列化器;null 使用 JSON */
serializer : PersistSerializer | null
}实际存储 key 为 keyPrefix + store.$id,例如 pinia:counter、pinia:user。
更多扩展
官方文档见 pinia.vuejs.org。本仓库用的是单文件移植版,API 与官方 Setup Store 一致。后续若要升级,替换 uni_modules/x-pinia-s/js_sdk/pinia.js 即可,持久化插件可继续用。
