uni-app状态管理之Pinia
一、介绍
uni-app 内置了 Pinia ,Vue 2 项目暂不支持。
Pinia是 Vue 的存储库,它允许您跨组件、页面共享状态。在服务器端以及小型单页应用程序中,您也可以从使用 Pinia 中获得很多好处:
- Devtools 支持
- 追踪 actions、mutations 的时间线
- 在组件中展示它们所用到的 Store
- 让调试更容易的 Time travel
- 热模块更换
- 不必重载页面即可修改 Store
- 开发时可保持当前的 State
- 为 JS 开发者提供适当的 TypeScript 支持以及 自动补全 功能。
目录结构
├── pages
├── static
└── stores
└── mainStore.js
├── App.vue
├── main.js
├── manifest.json
├── pages.json
└── uni.scss
二、使用
1、定义pinia管理的仓库
// store/mainStore.js import { defineStore } from 'pinia'; export const useMainStore = defineStore('main', { state: () => ({ userCount: 0 // 用户数量 }), getters: { doubledCount: state => state.userCount * 2, }, actions: { increment() { this.userCount++; } }, });
2、在main.js声明
import App from './App' import { createSSRApp } from 'vue' import store from '@/store/index.js'; import * as Pinia from 'pinia'; export function createApp() { const app = createSSRApp(App); app.use(store); // vuex与Pinia不冲突,可以一起使用 app.use(Pinia.createPinia()); return { app, Pinia, // 此处必须将 Pinia 返回 } }
3、在组件中使用,三种方式修改state的值
<template> <view class="content"> <!-- 直接从 store 中访问 state --> <text>当前用户数量有: {{ mainStore.userCount }}</text> <text>双倍用户数量有: {{ mainStore.doubledCount }}</text> <text><button @click="addUser1">直接修改用户数</button></text> <text><button @click="addUser2">$patch修改用户数</button></text> <text><button @click="addUser3">action修改用户数</button></text> </view> </template> <script setup lang="ts"> import { computed, onMounted, ref } from 'vue'; import { useMainStore } from '@/store/mainStore.js' const mainStore= useMainStore(); function addUser1() { // 1、直接修改state的值 mainStore.userCount++ } function addUser2() { // 2、$patch修改state的值 mainStore.$patch({ userCount: mainStore.userCount + 1 }) } function addUser3() { // 3、action修改state的值 mainStore.increment() } </script> <style> .content { display: flex; flex-direction: column; align-items: center; justify-content: center; } </style>
4、如果你还不熟悉 setup() 函数和组合式 API,Pinia 也提供了一组类似 Vuex 的 映射 state 的辅助函数。
你可以用和之前一样的方式来定义 Store,然后通过 mapStores()、mapState() 或 mapActions() 访问:
// store/counterStore.js const useCounterStore = defineStore('counter', { state: () => ({ count: 0 }), getters: { double: (state) => state.count * 2, }, actions: { increment() { this.count++ }, }, }) // store/userStore.js const useUserStore = defineStore('user', { // ... }) // 组件中使用 import { mapState, mapStores, mapActions } from 'pinia' import { useCounterStore } from '@/store/counterStore.js' import { useUserStore } from '@/store/userStore.js' export default defineComponent({ computed: { // 允许访问 this.counterStore 和 this.userStore ...mapStores(useCounterStore, useUserStore) // 允许读取 this.count 和 this.double ...mapState(useCounterStore, ['count', 'double']), }, methods: { // 允许读取 this.increment() ...mapActions(useUserStore, ['increment']), }, })
三、vuex与Pinia区别
1、模块化设计与架构差异
-
模块化复杂度
- Vuex:采用五模块设计(States、Mutations、Getters、Actions、Modules),需通过
mutations
同步修改状态,actions
处理异步操作,流程相对繁琐。 - Pinia:仅需三模块(States、Getters、Actions),允许直接在
actions
中同步或异步修改状态,API更简洁直观。
- Vuex:采用五模块设计(States、Mutations、Getters、Actions、Modules),需通过
-
架构模式
- Vuex:全局单例模式,所有组件共享单一状态树,适合集中式管理复杂状态。
- Pinia:分离式设计,每个组件可拥有独立store实例,支持扁平化模块拆分,更灵活。
2、兼容性与技术栈支持
-
Vue版本适配
- Vuex:主要支持Vue 2,Vue 3需使用Vuex 4.x,兼容性受限。
- Pinia:专为Vue 3设计,深度集成Composition API,不支持Vue 2。
-
TypeScript支持
- Vuex:需额外配置类型声明,类型推断较弱。
- Pinia:原生支持TypeScript,类型推断更完善,适合类型安全开发。
3、性能与开发体验
-
体积与性能
- Pinia:体积约1KB,采用ES6语法优化,性能更优。
- Vuex:体积较大,但稳定性强,适合对性能要求不苛刻的场景。
-
开发友好性
- Pinia:语法接近Vue组件,减少样板代码,适合快速开发和初学者。
- Vuex:严格遵循Flux架构,适合需要强规范的大型项目。
4、适用场景总结
工具 | 推荐场景 | 核心优势 |
---|---|---|
Vuex | 大型复杂项目、Vue 2迁移项目 | 严格状态管理、丰富插件生态 |
Pinia | Vue 3项目、快速原型开发 | 轻量灵活、TypeScript友好 |
选择建议:若项目基于Vue 3且追求开发效率,优先选择Pinia;若需维护Vue 2遗留系统或复杂状态逻辑,Vuex更稳妥。