在 UniApp 跨端开发中,状态管理一直是一个绕不开的话题。早期 Vuex 是官方推荐方案,但随着 Vue3 生态的成熟,Pinia 凭借更简洁的 API、更好的 TypeScript 支持和模块化设计,逐渐成为主流选择。本文将带你从零开始,在 UniApp 中落地 Pinia,并重点解决多端环境下的状态持久化问题。
为什么在 UniApp 中选择 Pinia
Pinia 是 Vue 官方团队推荐的新一代状态管理库,相比 Vuex 有以下几个明显优势:
- 更简洁的 API:去掉了 mutation,只有 state、getter 和 action,写法更接近组合式函数。
- 完整的 TypeScript 支持:类型推断友好,无需额外配置。
- 模块化天然支持:每个 store 独立定义,无需嵌套模块。
- 体积更小:压缩后仅约 1KB 左右,对小程序包体积友好。
在 UniApp 中,无论是 H5、小程序还是 App 端,Pinia 都能良好运行。尤其是 UniApp 对 Vue3 的支持已经非常稳定,使用 Pinia 几乎没有额外成本。
环境准备与安装
首先确保你的 UniApp 项目基于 Vue3 创建。如果是 HBuilderX 创建的项目,选择 Vue3 版本即可。然后安装 Pinia:
npm install pinia
# 或者
yarn add pinia
如果你使用的是 UniApp 的 Vite 版本,Pinia 可以直接使用;如果是 webpack 版本,建议升级到 Vue3 + Vite 模板以获得更好的开发体验。
在 UniApp 中注册 Pinia
在 main.js 或 main.ts 中注册 Pinia:
import { createSSRApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
export function createApp() {
const app = createSSRApp(App)
const pinia = createPinia()
app.use(pinia)
return { app }
}
注意 UniApp 的入口文件导出的是 createApp 函数,而不是直接创建 app 实例。这是 UniApp 为了兼容多端渲染所做的封装,Pinia 的注册方式与普通 Vue3 项目一致。
定义一个 Store
在 stores 目录下创建 user.js:
import { defineStore } from 'pinia'
export const useUserStore = defineStore('user', {
state: () => ({
token: '',
userInfo: null,
theme: 'light'
}),
getters: {
isLogin: (state) => !!state.token
},
actions: {
setToken(token) {
this.token = token
},
setUserInfo(info) {
this.userInfo = info
},
logout() {
this.token = ''
this.userInfo = null
}
}
})
在组件中使用:
<script setup>
import { useUserStore } from '@/stores/user'
const userStore = useUserStore()
</script>
<template>
<view>{{ userStore.isLogin ? '已登录' : '未登录' }}</view>
</template>
持久化方案的必要性
Pinia 的状态默认保存在内存中,页面刷新或小程序冷启动后会丢失。对于 token、用户信息、主题设置等数据,必须做持久化。UniApp 提供了 uni.setStorageSync 和 uni.getStorageSync,可以跨端使用,这是持久化的基础。
常见的持久化思路有两种:
- 手动持久化:在 action 中手动写入和读取 storage。
- 插件自动持久化:使用
pinia-plugin-persistedstate或自定义插件。
手动方式简单但重复代码多,推荐使用插件方案。
使用 pinia-plugin-persistedstate
安装插件:
npm install pinia-plugin-persistedstate
在 main.js 中注册:
import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)
然后在 store 中配置 persist:
export const useUserStore = defineStore('user', {
state: () => ({
token: '',
userInfo: null
}),
persist: {
key: 'user-store',
storage: {
getItem: (key) => uni.getStorageSync(key),
setItem: (key, value) => uni.setStorageSync(key, value)
},
paths: ['token', 'userInfo']
}
})
这里的关键是自定义 storage,因为默认插件使用 localStorage,在小程序和 App 端不存在。通过传入 uni.getStorageSync 和 uni.setStorageSync,即可实现多端兼容。
自定义持久化插件的实现
如果你不想引入额外依赖,也可以自己写一个简单的持久化插件:
export function persistPlugin({ store, options }) {
const persist = options.persist
if (!persist) return
const key = persist.key || store.$id
const paths = persist.paths || Object.keys(store.$state)
// 恢复
const saved = uni.getStorageSync(key)
if (saved) {
try {
const data = JSON.parse(saved)
const patch = {}
paths.forEach((p) => {
if (data[p] !== undefined) patch[p] = data[p]
})
store.$patch(patch)
} catch (e) {
console.error('持久化恢复失败', e)
}
}
// 订阅变化
store.$subscribe((_mutation, state) => {
const data = {}
paths.forEach((p) => {
data[p] = state[p]
})
uni.setStorageSync(key, JSON.stringify(data))
})
}
注册方式:
pinia.use(persistPlugin)
这个插件逻辑清晰,适合对包体积敏感或需要深度定制的项目。
多端注意事项
- 小程序:storage 有 10MB 上限,避免存储大对象。建议只持久化必要字段。
- App 端:
uni.setStorageSync是同步的,频繁写入可能影响性能,可考虑防抖。 - H5 端:
uni.setStorageSync底层使用 localStorage,注意同源策略。 - SSR:如果使用 UniApp 的 SSR 模式,需要在客户端挂载后再恢复状态,避免服务端读取不到 storage。
总结
在 UniApp 中落地 Pinia 并不复杂,核心在于两点:正确注册 Pinia 实例和解决多端持久化。通过 pinia-plugin-persistedstate 配合 UniApp 的 storage API,可以快速实现跨端持久化;如果追求轻量,自定义插件也是不错的选择。建议根据项目规模选择方案,并在持久化时注意字段裁剪和性能优化,让状态管理真正服务于业务,而不是成为负担。
未经允许不得转载:任鹏个人博客 » UniApp 中 Pinia 状态管理的落地与持久化方案


朋友圈点赞图在线生成源码