应用全局状态管理:AppStorage 与 LocalStorage 实战与避坑
·
应用全局状态管理:AppStorage 与 LocalStorage 实战与避坑
前言
在很多教程里,@State、@Prop、@Link、@Provide/@Consume 被反复讲解,但“跨页面、跨组件树、甚至跨 Ability”的全局状态该怎么存,却常被一笔带过。鸿蒙提供了两套全局单例:AppStorage(应用级,进程内全局)与 LocalStorage(页面级/Ability 级,可随路由传递)。本文讲清两者的区别、适用边界与高频踩坑。
问题描述
开发者常遇到这些问题:
- 在 A 页面登录后修改了用户信息,跳到 B 页面读不到。
- 用
@StorageLink绑定了AppStorage,却发现某个页面改了值别的页面不刷新。 - 想做“夜间模式开关”全局生效,但每个页面都各自维护一份状态,互相不同步。
- 把复杂对象塞进
AppStorage,结果序列化报错或更新不触发。
这些问题的本质是:没分清“全局可见范围”和“可观察性来源”。
细节解析
AppStorage:应用级的单例,运行在 UI 主线程,整个应用任意组件通过 @StorageLink / @StorageProp 都能访问。适合“全局配置、登录态、主题”等需要全应用同步的状态。
LocalStorage:与某个 Ability 或某个 Router 页面栈绑定,通过 router 的 params 或 LocalStorage 实例在页面间传递,适合“一组相关页面共享、但与其它 Ability 无关”的状态(如一个业务流的表单草稿)。
关键装饰器:
@StorageLink('key'):双向绑定AppStorage,本组件修改会写回,其它绑定同一 key 的组件会刷新。@StorageProp('key'):单向(只读快照),只从AppStorage读,本地改不影响全局。@LocalStorageLink('key')/@LocalStorageProp('key'):同上,但作用于LocalStorage。
高频坑:
- key 必须是
string,且全局唯一;重复 key 会互相覆盖。 AppStorage存的是“可观察的引用”,修改对象内部属性不会触发刷新——要整体替换对象或用@Observed+@ObjectLink。- 不要在
AppStorage里存大对象/非序列化数据;它不适合当数据库用(持久化请用Preferences/RdbStore)。 AppStorage是内存态,进程被杀即丢失,需要持久化的全局态要配合Preferences在启动时回填。
示例代码
// 在 Ability 或入口处初始化全局主题(仅一次)
AppStorage.setOrCreate('theme', 'light')
AppStorage.setOrCreate('userName', '乔喜洋')
// 页面 A:修改全局主题
@Entry
@Component
struct PageA {
@StorageLink('theme') theme: string = 'light'
build() {
Column() {
Text('当前主题:' + this.theme)
Button(this.theme === 'light' ? '切到夜间' : '切到白天')
.onClick(() => {
this.theme = this.theme === 'light' ? 'dark' : 'light'
})
}.padding(20)
}
}
// 页面 B:自动跟随主题变化(无需手动传参)
@Entry
@Component
struct PageB {
@StorageLink('theme') theme: string = 'light'
@StorageProp('userName') userName: string = ''
build() {
Column() {
Text(`你好,${this.userName}`)
Text('主题(只读):' + this.theme)
.fontColor(this.theme === 'dark' ? '#fff' : '#000')
}.padding(20)
}
}
要点:
PageA改theme,PageB立即刷新——这就是@StorageLink的全局联动。PageB用@StorageProp读userName表示“只读展示”,避免误改全局。- 复杂对象示例:
// 错误:改内部属性不刷新
let u = AppStorage.get('user') as User
u.name = 'new' // AppStorage 不感知
// 正确:整体替换
AppStorage.set('user', { ...u, name: 'new' })
总结
- 全应用共享、需要跨页面联动 →
AppStorage+@StorageLink。 - 只读展示全局态 →
@StorageProp,防止误写。 - 一组相关页面共享、不需要全局 →
LocalStorage。 - 改对象要整体替换,或配合
@Observed/@ObjectLink做深层观察。 - 持久化全局态用
Preferences,启动时回填AppStorage,不要让AppStorage充当数据库。
把“全局态”和“持久化”两套职责拆开,状态管理会清晰很多,也少踩一大半坑。
更多推荐




所有评论(0)