状态篇
unibest - 官方文档地址
:unibest.tech
本文主要介绍了全局状态管理 pinia
和 简单状态 ref
+ reactive
。
pinia
unibest
已经内置了 Pinia
+ pinia-plugin-persistedstate
(数据持久化插件),并提供了开箱即用的示例。
兼容性处理
本身 pinia-plugin-persistedstate
是不支持 uniapp
的,但是 pinia-plugin-persistedstate
提供了修改 storage
存储 API 的方式(默认是 localStorage
,是一个 WEB API
,非H5端
不支持),目前 unibest
已经处理好了。关键代码如下:
import { createPinia } from 'pinia'
import { createPersistedState } from 'pinia-plugin-persistedstate' // 数据持久化
const store = createPinia()
store.use(
createPersistedState({
storage: {
getItem: uni.getStorageSync, // 看这里
setItem: uni.setStorageSync, // 看这里
},
}),
)
定义 pinia
全局状态
src/store/xxx.ts
里面编写代码,如下是 src/store/count.ts
文件。
注意 defineStore
第三个参数可以设置是否需要持久化,默认不需要。
import { defineStore } from 'pinia'
import { ref } from 'vue'
export const useCountStore = defineStore(
'count',
() => {
const count = ref(0)
const increment = () => {
count.value++
}
const decrement = () => {
count.value--
}
const reset = () => {
count.value = 0
}
return {
count,
decrement,
increment,
reset,
}
},
{
// 如果需要持久化就写 true, 不需要持久化就写 false(或者去掉这个配置项)
persist: true,
},
)
请不要随意把数据丢到
pinia
,能不用就不用。简单状态尽量使用ref
或者reactive
。
使用 pinia
全局状态
在 vue
文件中就可以使用了,如下是 src/pages/demo.vue
文件:
<template>
<view class="flex justify-center items-center text-blue-500 mt-4 mb-4">
<view class="w-20">Count: {{ countStore.count }}</view>
<button class="ml-2 mr-2" @click="countStore.decrement">-1</button>
<button class="ml-2 mr-2" @click="countStore.increment">+1</button>
<button class="ml-2 mr-2" @click="countStore.reset">重置</button>
</view>
</template>
<script lang="ts" setup>
import { useCountStore } from '@/store'
const countStore = useCountStore()
</script>
简单状态
你可以直接使用 Vue
提供的 ref
或 reactive
方法来做简单状态管理。
ref
如下是 src/pages/demo/useCount.ts
文件,定义简单状态。
// 全局状态
const globalCount = ref(1)
export function useCount() {
// 本地状态
const localCount = ref(1)
function increment() {
globalCount.value++
localCount.value++
}
return {
globalCount,
localCount,
increment,
}
}
如下是 src/pages/demo/index.vue
,与 ref
简单状态文件放到同一个目录下,方便管理。
<script setup lang="ts">
import useCount from './useCount.ts'
const { globalCount, localCount, increment } = useCount()
</script>
<template>
<button @click="increment()">
{{ globalCount }}
{{ localCount }}
</button>
</template>
reactive
reactive
与 ref
类似。
如下是 src/pages/demo/count.ts
文件,定义状态。
export const countStore = reactive({
count: 0,
increment() {
this.count++
},
})
如下是 src/pages/demo/index.vue
,与 reactive
简单状态文件放到同一个目录下,方便管理。
<script setup lang="ts">
import { countStore } from './count.ts'
</script>
<template>
<button @click="countStore.increment()">
{{ countStore.count }}
</button>
</template>
unibest 内置代码(选读)
- src/store/user.ts
内置用户状态
import { defineStore } from 'pinia'
import { ref } from 'vue'
const initState = { nickname: '', avatar: '' }
export const useUserStore = defineStore(
'user',
() => {
const userInfo = ref<IUserInfo>({ ...initState })
const setUserInfo = (val: IUserInfo) => {
userInfo.value = val
}
const clearUserInfo = () => {
userInfo.value = { ...initState }
}
// 一般没有reset需求,不需要的可以删除
const reset = () => {
userInfo.value = { ...initState }
}
const isLogined = computed(() => !!userInfo.value.token)
return {
userInfo,
setUserInfo,
clearUserInfo,
isLogined,
reset,
}
},
{
persist: true,
},
)
- src/store/index.ts
全局状态统一输出
import { createPinia } from 'pinia'
import { createPersistedState } from 'pinia-plugin-persistedstate' // 数据持久化
const store = createPinia()
store.use(
createPersistedState({
storage: {
getItem: uni.getStorageSync,
setItem: uni.setStorageSync,
},
}),
)
export default store
// 模块统一导出
export * from './user'
- src/interceptors/request.ts
请求拦截器里面有用到用户状态
/* eslint-disable no-param-reassign */
import qs from 'qs'
import { useUserStore } from '@/store'
import { platform } from '@/utils/platform'
export type CustomRequestOptions = UniApp.RequestOptions & {
query?: Record<string, any>
/** 出错时是否隐藏错误提示 */
hideErrorToast?: boolean
} & IUniUploadFileOptions // 添加uni.uploadFile参数类型
// 请求基准地址
const baseUrl = import.meta.env.VITE_SERVER_BASEURL
// 拦截器配置
const httpInterceptor = {
// 拦截前触发
invoke(options: CustomRequestOptions) {
// 接口请求支持通过 query 参数配置 queryString
if (options.query) {
const queryStr = qs.stringify(options.query)
if (options.url.includes('?')) {
options.url += `&${queryStr}`
} else {
options.url += `?${queryStr}`
}
}
// 非 http 开头需拼接地址
if (!options.url.startsWith('http')) {
// #ifdef H5
console.log(__VITE_APP_PROXY__)
if (JSON.parse(__VITE_APP_PROXY__)) {
// 啥都不需要做
} else {
options.url = baseUrl + options.url
}
// #endif
// 非H5正常拼接
// #ifndef H5
options.url = baseUrl + options.url
// #endif
// TIPS: 如果需要对接多个后端服务,也可以在这里处理,拼接成所需要的地址
}
// 1. 请求超时
options.timeout = 10000 // 10s
// 2. (可选)添加小程序端请求头标识
options.header = {
platform, // 可选,与 uniapp 定义的平台一致,告诉后台来源
...options.header,
}
// 3. 添加 token 请求头标识
const userStore = useUserStore()
const { token } = userStore.userInfo as unknown as IUserInfo
if (token) {
options.header.Authorization = `Bearer ${token}`
}
},
}
export const requestInterceptor = {
install() {
// 拦截 request 请求
uni.addInterceptor('request', httpInterceptor)
// 拦截 uploadFile 文件上传
uni.addInterceptor('uploadFile', httpInterceptor)
},
}
其他可以看
unibest
代码,注释较多,简单易懂。
总结
本文介绍了 unibest
里面状态管理的 2
种方式:pinia
全局状态 和 ref\reactive
简单状态,分别演示了如何定义状态和使用状态。
注意需要灵活使用 pinia
和 简单状态
,局部的状态尽量使用 简单状态
的方式来处理,减少 pinia
里面全局变量的数量。
全文完~
unibest 链接地址
最后贴几个链接,方便大家。
文档地址:codercup.github.io/unibest-doc…
github
地址:github.com/codercup/un…
gitee
地址:gitee.com/codercup/un…
微信交流群
因不能贴引流二维码,有需要的同学请看官方文档微信群 传送门。