---
title: "v0.2.0 架构升级：class + reactive 重塑状态管理 - Angryecho"
description: "v0.2.0 为重大架构升级：store 定义改为 class + reactive（class XxxStore extends PiniaStoreBase），state 用 reactive<T> 强类型包裹、派生值用 class getter、action 为普通 method——由此换来完整实例 API（$…"
canonical_url: "https://www.angryecho.com/c/qian_duan_she_qu/p/P2TBC4BAor8YTBcLnxVJi"
meta:
  "og:description": "v0.2.0 为重大架构升级：store 定义改为 class + reactive（class XxxStore extends PiniaStoreBase），state 用 reactive<T> 强类型包裹、派生值用 class getter、action 为普通 method——由此换来完整实例 API（$…"
  "og:image": "https://www.angryecho.com/_og/d/c_Post%2Ctitle_~5ZCQ5qe9572R%2Cdescription_~5ZCQ5qe95LiA5LiL77yM5bCx5LiK5ZCQ5qe9572R44CC%2CpostId_P2TBC4BAor8YTBcLnxVJi%2Crevision_~MjAyNi0xMS0wM1QwOTowMDo0NC4xOTU0ODZa%2Cp_Ii9jL3FpYW5fZHVhbl9zaGVfcXUvcC9QMlRCQzRCQW9yOFlUQmNMbnhWSmki%2Cs_oM872HQ1CvIrE99u.png"
  "og:image:height": "630"
  "og:image:type": image/png
  "og:image:width": "1200"
  "og:title": "v0.2.0 架构升级：class + reactive 重塑状态管理"
---

> Index of every page on this site: [llms.txt](https://www.angryecho.com/llms.txt)

# **v0.2.0 架构升级：class + reactive 重塑状态管理**

> v0.2.0 为**重大架构升级**：store 定义改为 class + reactive（`class XxxStore extends PiniaStoreBase`），state 用 `reactive<T>` 强类型包裹、派生值用 class getter、action 为普通 method——由此换来**完整实例 API**（`$patch` / `$reset` / `$subscribe` / `$onAction` / `$dispose` / `$id` / `$state` / `$save`）与**内置持久化插件**（`createPersistPlugin`：store 创建自动恢复、`$patch` / `$reset` / `$save` 自动落盘）。⚠️ 破坏性变更：0.1.0 setup 式 API（`storeToRefs` / 顶层 `patch` / `loadPersisted` 等）已移除，迁移对照见第四节。

## 一、为什么升级架构

v0.1.0 的 setup 式 + Ref 形态跑通了下限，但也撞上了天花板——两条平台硬约束：

- **UTS 无 Proxy、无反射**：store 对象不可动态挂方法、不可运行时枚举字段， `$patch` / `$subscribe` / `$onAction` / `$reset` 在 setup 式形态下全部无法实现（v0.1.0 只能裁掉）
- **新版 HBuilderX 编译器对 UTS 插件内运行时类 vue 符号（**`**Ref**`** /** `**watch**`** /** `**effectScope**`**）的 Kotlin import 生成失效**——云打包 Kotlin 编译直接 Unresolved

而 `reactive<T>` 在 UTS 中是**编译期展开**（生成属性代理类，getter/setter 内联依赖追踪），不受上述约束影响。class + reactive 因此成为 uni-app x 插件实现完整 Pinia 功能面的唯一可行架构。v0.2.0 完成架构转向，一次补齐：

| 能力 | v0.1.0 | v0.2.0 |
| --- | --- | --- |
| `$patch` / `$reset` | 顶层 `patch(mutator)` / ❌ | ✅ `$patch(partial)` / `$reset()`（`_doReset` 钩子） |
| `$subscribe` / `$onAction` | ❌（字段级 `watch` 替代） | ✅ 内置（快照分发 / `callAction` 追踪） |
| `$id` / `$state` / `$dispose` | 顶层函数映射 | ✅ 实例属性 / 方法 |
| `$save` 显式保存点 | — | ✅ |
| 持久化 | ❌ | ✅ 内置插件，零胶水 |

## 二、核心能力

### class 式 defineStore

```
import { reactive } from 'vue'
import { defineStore, PiniaStoreBase } from '@/uni_modules/ux-pinia'

export type CounterState = {
count: number
name: string
}

export class CounterStore extends PiniaStoreBase {
// state：reactive<T> 强类型包裹（字段为原始值，模板 / 脚本直接访问）
state: CounterState = reactive<CounterState>({ count: 0, name: 'pinia' })

// 派生值：class getter（每次求值，模板经 reactive 属性依赖收集自动更新）
get doubleCount(): number {
return this.state.count * 2
}

// constructor：super() 后必须 bindState(this.state)（$-API 与持久化的前提）
constructor() {
super()
this.bindState(this.state)
}

// actions = 普通 class method，直接修改 state
increment(): void {
this.state.count++
}
}

export const useCounterStore = defineStore<CounterStore>('counter', (): CounterStore => new CounterStore())
```

结构对齐 Pinia 官方 `state / getters / actions` 心智；模板事件绑定 class method 必须带括号（`@click="counter.increment()"`，Kotlin 端 method 不是值）。

### 完整实例 API（$-methods）

```
const counter = useCounterStore()

counter.$patch({ count: 10 } as UTSJSONObject)  // 批量修改（经 _hydrate 钩子装载）
counter.$reset()                                 // 重置（_doReset 钩子）
const unsub = counter.$subscribe((type: string, state: UTSJSONObject): void => {
// type = 'patch' | 'reset' | 'save'；state = _serialize() 快照
})
counter.$onAction((info: ActionInfo): void => { /* action 追踪 */ })
counter.$save()      // 显式保存点（direct 修改 state 后的落盘触发）
counter.$dispose()   // 注销，下次 useStore() 重建
counter.$id          // 'counter'
```

`$subscribe` 仅由 `$patch` / `$reset` / `$save` 触发（UTS 无全局订阅钩子）；direct 修改 state 后的关键操作请调用 `counter.$save()`。

### 内置持久化插件（零胶水）

`main.uts` 顶层登记一次，全部 store 生效：

```
import { createPinia, setActivePinia, createPersistPlugin } from '@/uni_modules/ux-pinia'

setActivePinia(createPinia().use(createPersistPlugin({
keyPrefix: 'ux-pinia:',
includeStores: null,               // null = 全部 store
excludeStores: new Array<string>(),
serializer: null                   // null = JSON 序列化
})))
```

需要持久化的 store 重写两个钩子（Template Method 契约）：

```
override _serialize(): UTSJSONObject {
// 落盘快照：只含需持久化的字段
return { token: this.state.token } as UTSJSONObject
}

override _hydrate(data: UTSJSONObject): void {
// 恢复回填：字段级判空（存储损坏 / 字段缺失 → 保留初始值）
if (data['token'] != null) {
this.state.token = data['token'] as string
}
}
```

**恢复**在 store 创建时自动发生；**落盘**由 `$patch` / `$reset` / `$save` 自动触发。对比旧版「每字段两行 ref / watch 胶水」的方案，持久化成本降为两个声明式钩子。存储后端可经 `setStorageAdapter` 替换（默认 uni storage，可换 unix-storage / 原生 preferences）；`clearPersistedState(storeId, keyPrefix)` 可清空单个 store。

### 免挂载单例与插件体系（一如既往）

模块级注册表保证应用级单例，跨页面共享状态，无需 `app.use`（实测原生端 `app.use` 不触发 install，免挂载是唯一双端一致的形态）；插件 `pinia.use(plugin)` 链式注册，`PiniaPluginContext`（`pinia` / `store` / `storeId`）对齐标准 Pinia——持久化插件本身就是插件体系的第一个内置成员。

## 三、平台支持现状

| 平台 | 状态 |
| --- | --- |
| Web | ✅ 全用例通过（基础用法 / 响应式 / 单例跨页面 / 实例 API / 跨 store / 订阅 / 插件 / 持久化） |
| Android | ✅ 蒸汽模式（vapor）云打包 Kotlin 编译链通过，真机用例复验中 |
| iOS / 鸿蒙 | ⏳ 代码全端同构（纯 UTS、无平台分支），待实测 |

关键实测裁决（驱动本次架构定稿）：`reactive<T>` 为编译期展开（Kotlin 生成正常）；运行时类 vue 符号（`Ref` / `ref` / `watch` / `effectScope`）在插件内 Kotlin import 生成失效（`effectScope` 被生成器静默丢弃——派生值因此用 getter 而非 computed）；模板 class method 绑定必须带括号；Kotlin 泛型擦除边界（error17）在库内收敛，业务侧零感知。

## 四、0.1.0 → 0.2.0 迁移对照

| v0.1.0（setup 式，已移除） | v0.2.0（class 式） |
| --- | --- |
| `type CounterStore = { count: Ref<number>, ... }` + setup 函数 | `class CounterStore extends PiniaStoreBase`（state = `reactive<T>` 字段） |
| 脚本 `store.count.value` / 模板 `storeToRefs` 解构 | `store.state.count` 直接读写，脚本模板同路径 |
| `patch(store, fn)` | `store.$patch(partial)` 或直接调用 action |
| 字段级 `watch(store.count, cb)` | `store.$subscribe(cb)` |
| 自定义 reset action | `store.$reset()`（`_doReset` 钩子） |
| `loadPersisted` / `savePersisted` + 每字段 ref / watch 胶水 | `createPersistPlugin` + `_serialize` / `_hydrate` 双钩子 |
| `getStoreId(store)` / `dispose(store)` | `store.$id` / `store.$dispose()`（顶层函数仍保留） |

## 五、快速上手

```
pnpm add @meng-xi/unix-pinia
mkdir -p uni_modules && cp -R node_modules/@meng-xi/unix-pinia uni_modules/ux-pinia
```

插件市场搜索 `ux-pinia` 导入亦可。定义 store 见第二节 class 式示例；页面直接消费 `counter.state.count` 与 getter。不想搭工程？**安卓真机可直接下载体验 App**： [下载体验 App（APK）](https://link.juejin.cn/?target=https%3A%2F%2Fmp-b8b8347a-48e9-434d-8302-3e9d99c2cb01.cdn.bspapp.com%2Fcloudstorage%2Fapp-build-pkg%2F1793456655694-__UNI__0AA2919_1793456648910.apk "https://mp-b8b8347a-48e9-434d-8302-3e9d99c2cb01.cdn.bspapp.com/cloudstorage/app-build-pkg/1793456655694-__UNI__0AA2919_1793456648910.apk")——示例工程云打包产物（蒸汽模式），安装后进入各功能页即可在真机运行全部用例。

## 六、文档与资源

- 📖 [完整文档](https://link.juejin.cn/?target=https%3A%2F%2Fmengxi-studio.github.io%2Funix-pinia%2F "https://mengxi-studio.github.io/unix-pinia/")（指南 9 篇 + API 3 篇，中英双语，从入门到精通）
- 📝 [更新日志](https://link.juejin.cn/?target=https%3A%2F%2Fgithub.com%2FMengXi-Studio%2Funix-pinia%2Fblob%2Fmaster%2Fpackages%2Fdocs%2Fsrc%2Fchangelog.md "https://github.com/MengXi-Studio/unix-pinia/blob/master/packages/docs/src/changelog.md")

## 相关链接

- [示例工程 packages/playground](https://link.juejin.cn/?target=https%3A%2F%2Fgithub.com%2FMengXi-Studio%2Funix-pinia%2Ftree%2Fmaster%2Fpackages%2Fplayground "https://github.com/MengXi-Studio/unix-pinia/tree/master/packages/playground")（首页分组导航 + 9 个功能验证页，HBuilderX 发行 Web / 云打包验证）
- [API 参考](https://link.juejin.cn/?target=https%3A%2F%2Fmengxi-studio.github.io%2Funix-pinia%2Fapi%2Ffunctions.html "https://mengxi-studio.github.io/unix-pinia/api/functions.html")

欢迎反馈与共建： [GitHub](https://link.juejin.cn/?target=https%3A%2F%2Fgithub.com%2FMengXi-Studio%2Funix-pinia "https://github.com/MengXi-Studio/unix-pinia")

排序方式 :

### **成为第一条评论！**

Nobody's responded to this post yet. Add your thoughts and get the conversation going.

```json
{"@context":"https://schema.org","@graph":[{"@id":"https://www.angryecho.com/c/qian_duan_she_qu/p/P2TBC4BAor8YTBcLnxVJi#post","@type":"DiscussionForumPosting","commentCount":0,"dateModified":"2026-11-03T09:00:44.195Z","datePublished":"2026-10-31T16:24:34.145Z","description":"v0.2.0 为重大架构升级：store 定义改为 class + reactive（class XxxStore extends PiniaStoreBase），state 用 reactive\u003CT> 强类型包裹、派生值用 class getter、action 为普通 method——由此换来完整实例 API（$…","headline":"v0.2.0 架构升级：class + reactive 重塑状态管理","isPartOf":"https://www.angryecho.com/c/qian_duan_she_qu","mainEntityOfPage":"https://www.angryecho.com/c/qian_duan_she_qu/p/P2TBC4BAor8YTBcLnxVJi","text":"v0.2.0 为重大架构升级：store 定义改为 class + reactive（class XxxStore extends PiniaStoreBase），state 用 reactive\u003CT> 强类型包裹、派生值用 class getter、action 为普通 method——由此换来完整实例 API（$patch / $reset / $subscribe / $onAction / $dispose / $id / $state / $save）与内置持久化插件（createPersistPlugin：store 创建自动恢复、$patch / $reset / $save 自动落盘）。⚠️ 破坏性变更：0.1.0 setup 式 API（storeToRefs / 顶层 patch / loadPersisted 等）已移除，迁移对照见第四节。\n\n一、为什么升级架构\n\nv0.1.0 的 setup 式 + Ref 形态跑通了下限，但也撞上了天花板——两条平台硬约束：\n\n\n\n\n\nUTS 无 Proxy、无反射：store 对象不可动态挂方法、不可运行时枚举字段，$patch / $subscribe / $onAction / $reset 在 setup 式形态下全部无法实现（v0.1.0 只能裁掉）\n\n\n\n新版 HBuilderX 编译器对 UTS 插件内运行时类 vue 符号（Ref / watch / effectScope）的 Kotlin import 生成失效——云打包 Kotlin 编译直接 Unresolved\n\n而 reactive\u003CT> 在 UTS 中是编译期展开（生成属性代理类，getter/setter 内联依赖追踪），不受上述约束影响。class + reactive 因此成为 uni-app x 插件实现完整 Pinia 功能面的唯一可行架构。v0.2.0 完成架构转向，一次补齐：\n\n\n\n\n\n\n\n能力\n\n\n\nv0.1.0\n\n\n\nv0.2.0\n\n\n\n\n\n$patch / $reset\n\n\n\n顶层 patch(mutator) / ❌\n\n\n\n✅ $patch(partial) / $reset()（_doReset 钩子）\n\n\n\n\n\n$subscribe / $onAction\n\n\n\n❌（字段级 watch 替代）\n\n\n\n✅ 内置（快照分发 / callAction 追踪）\n\n\n\n\n\n$id / $state / $dispose\n\n\n\n顶层函数映射\n\n\n\n✅ 实例属性 / 方法\n\n\n\n\n\n$save 显式保存点\n\n\n\n—\n\n\n\n✅\n\n\n\n\n\n持久化\n\n\n\n❌\n\n\n\n✅ 内置插件，零胶水\n\n二、核心能力\n\nclass 式 defineStore\n\nimport { reactive } from 'vue'\nimport { defineStore, PiniaStoreBase } from '@/uni_modules/ux-pinia'\n\nexport type CounterState = {\ncount: number\nname: string\n}\n\nexport class CounterStore extends PiniaStoreBase {\n// state：reactive\u003CT> 强类型包裹（字段为原始值，模板 / 脚本直接访问）\nstate: CounterState = reactive\u003CCounterState>({ count: 0, name: 'pinia' })\n\n// 派生值：class getter（每次求值，模板经 reactive 属性依赖收集自动更新）\nget doubleCount(): number {\nreturn this.state.count * 2\n}\n\n// constructor：super() 后必须 bindState(this.state)（$-API 与持久化的前提）\nconstructor() {\nsuper()\nthis.bindState(this.state)\n}\n\n// actions = 普通 class method，直接修改 state\nincrement(): void {\nthis.state.count++\n}\n}\n\nexport const useCounterStore = defineStore\u003CCounterStore>('counter', (): CounterStore => new CounterStore())\n\n结构对齐 Pinia 官方 state / getters / actions 心智；模板事件绑定 class method 必须带括号（@click=\"counter.increment()\"，Kotlin 端 method 不是值）。\n\n完整实例 API（$-methods）\n\nconst counter = useCounterStore()\n\ncounter.$patch({ count: 10 } as UTSJSONObject)  // 批量修改（经 _hydrate 钩子装载）\ncounter.$reset()                                 // 重置（_doReset 钩子）\nconst unsub = counter.$subscribe((type: string, state: UTSJSONObject): void => {\n// type = 'patch' | 'reset' | 'save'；state = _serialize() 快照\n})\ncounter.$onAction((info: ActionInfo): void => { /* action 追踪 */ })\ncounter.$save()      // 显式保存点（direct 修改 state 后的落盘触发）\ncounter.$dispose()   // 注销，下次 useStore() 重建\ncounter.$id          // 'counter'\n\n$subscribe 仅由 $patch / $reset / $save 触发（UTS 无全局订阅钩子）；direct 修改 state 后的关键操作请调用 counter.$save()。\n\n内置持久化插件（零胶水）\n\nmain.uts 顶层登记一次，全部 store 生效：\n\nimport { createPinia, setActivePinia, createPersistPlugin } from '@/uni_modules/ux-pinia'\n\nsetActivePinia(createPinia().use(createPersistPlugin({\nkeyPrefix: 'ux-pinia:',\nincludeStores: null,               // null = 全部 store\nexcludeStores: new Array\u003Cstring>(),\nserializer: null                   // null = JSON 序列化\n})))\n\n需要持久化的 store 重写两个钩子（Template Method 契约）：\n\noverride _serialize(): UTSJSONObject {\n// 落盘快照：只含需持久化的字段\nreturn { token: this.state.token } as UTSJSONObject\n}\n\noverride _hydrate(data: UTSJSONObject): void {\n// 恢复回填：字段级判空（存储损坏 / 字段缺失 → 保留初始值）\nif (data['token'] != null) {\nthis.state.token = data['token'] as string\n}\n}\n\n恢复在 store 创建时自动发生；落盘由 $patch / $reset / $save 自动触发。对比旧版「每字段两行 ref / watch 胶水」的方案，持久化成本降为两个声明式钩子。存储后端可经 setStorageAdapter 替换（默认 uni storage，可换 unix-storage / 原生 preferences）；clearPersistedState(storeId, keyPrefix) 可清空单个 store。\n\n免挂载单例与插件体系（一如既往）\n\n模块级注册表保证应用级单例，跨页面共享状态，无需 app.use（实测原生端 app.use 不触发 install，免挂载是唯一双端一致的形态）；插件 pinia.use(plugin) 链式注册，PiniaPluginContext（pinia / store / storeId）对齐标准 Pinia——持久化插件本身就是插件体系的第一个内置成员。\n\n三、平台支持现状\n\n\n\n\n\n\n\n平台\n\n\n\n状态\n\n\n\n\n\nWeb\n\n\n\n✅ 全用例通过（基础用法 / 响应式 / 单例跨页面 / 实例 API / 跨 store / 订阅 / 插件 / 持久化）\n\n\n\n\n\nAndroid\n\n\n\n✅ 蒸汽模式（vapor）云打包 Kotlin 编译链通过，真机用例复验中\n\n\n\n\n\niOS / 鸿蒙\n\n\n\n⏳ 代码全端同构（纯 UTS、无平台分支），待实测\n\n关键实测裁决（驱动本次架构定稿）：reactive\u003CT> 为编译期展开（Kotlin 生成正常）；运行时类 vue 符号（Ref / ref / watch / effectScope）在插件内 Kotlin import 生成失效（effectScope 被生成器静默丢弃——派生值因此用 getter 而非 computed）；模板 class method 绑定必须带括号；Kotlin 泛型擦除边界（error17）在库内收敛，业务侧零感知。\n\n四、0.1.0 → 0.2.0 迁移对照\n\n\n\n\n\n\n\nv0.1.0（setup 式，已移除）\n\n\n\nv0.2.0（class 式）\n\n\n\n\n\ntype CounterStore = { count: Ref\u003Cnumber>, ... } + setup 函数\n\n\n\nclass CounterStore extends PiniaStoreBase（state = reactive\u003CT> 字段）\n\n\n\n\n\n脚本 store.count.value / 模板 storeToRefs 解构\n\n\n\nstore.state.count 直接读写，脚本模板同路径\n\n\n\n\n\npatch(store, fn)\n\n\n\nstore.$patch(partial) 或直接调用 action\n\n\n\n\n\n字段级 watch(store.count, cb)\n\n\n\nstore.$subscribe(cb)\n\n\n\n\n\n自定义 reset action\n\n\n\nstore.$reset()（_doReset 钩子）\n\n\n\n\n\nloadPersisted / savePersisted + 每字段 ref / watch 胶水\n\n\n\ncreatePersistPlugin + _serialize / _hydrate 双钩子\n\n\n\n\n\ngetStoreId(store) / dispose(store)\n\n\n\nstore.$id / store.$dispose()（顶层函数仍保留）\n\n五、快速上手\n\npnpm add @meng-xi/unix-pinia\nmkdir -p uni_modules && cp -R node_modules/@meng-xi/unix-pinia uni_modules/ux-pinia\n\n插件市场搜索 ux-pinia 导入亦可。定义 store 见第二节 class 式示例；页面直接消费 counter.state.count 与 getter。不想搭工程？安卓真机可直接下载体验 App：下载体验 App（APK）——示例工程云打包产物（蒸汽模式），安装后进入各功能页即可在真机运行全部用例。\n\n六、文档与资源\n\n\n\n\n\n📖 完整文档（指南 9 篇 + API 3 篇，中英双语，从入门到精通）\n\n\n\n📝 更新日志\n\n相关链接\n\n\n\n\n\n示例工程 packages/playground（首页分组导航 + 9 个功能验证页，HBuilderX 发行 Web / 云打包验证）\n\n\n\nAPI 参考\n\n欢迎反馈与共建：GitHub","url":"https://www.angryecho.com/c/qian_duan_she_qu/p/P2TBC4BAor8YTBcLnxVJi","author":{"@type":"Person","name":"PedroQue99","url":"https://www.angryecho.com/u/F2OPedroQue99"},"interactionStatistic":[{"@type":"InteractionCounter","interactionType":"https://schema.org/LikeAction","userInteractionCount":0},{"@type":"InteractionCounter","interactionType":"https://schema.org/DislikeAction","userInteractionCount":0},{"@type":"InteractionCounter","interactionType":"https://schema.org/ViewAction","userInteractionCount":0},{"@type":"InteractionCounter","interactionType":"https://schema.org/ShareAction","userInteractionCount":0}]}]}
```

## Sitemap

See the full [sitemap](https://www.angryecho.com/sitemap.md) for all pages.
