ArkTS 进阶之道(24):LocalStorage 页面级状态边界——为啥同页面多组件共享页面卸载就销毁
ArkTS 进阶之道(24):LocalStorage 页面级状态边界——为啥同页面多组件共享页面卸载就销毁
本文是「ArkTS 进阶之道」系列第 24 篇,续「ArkUI 状态联动」深水区。上篇讲 AppStorage 应用级状态存储槽边界(所有页面共享,页面卸载状态仍存在)。本文讲页面级状态边界:LocalStorage 页面级局部状态存储——根因在同页面多组件共享,页面卸载就销毁。能力系列篇 24 讲过 LocalStorage 怎么用,本文讲为哈 LocalStorage 页面级状态合法 AppStorage 应用级状态跨页面共享冗余——根因在页面级状态存储槽。
一、开篇:LocalStorage 不是应用级 AppStorage,是页面级局部状态存储
你写 React 时,页面级状态是「useState 魔法」(组件卸载 state 销毁):
// React 页面级状态:useState(组件卸载 state 销毁) function Page() { const [count, setCount] = useState(0) // 页面级 state return <button onClick={() => setCount(count + 1)}>count={count}</button> } // React 页面级状态:useState(组件卸载 state 销毁,不跨页面共享)你写鸿蒙 ArkTS 时,LocalStorage页面级局部状态存储——同页面多组件共享,页面卸载就销毁:
// ArkTS LocalStorage 页面级局部状态存储 interface LocalState { localCount: number; localTheme: string } const localStorage = new LocalStorage({ localCount: 0, localTheme: '#52C41A' } as LocalState) @Component struct ChildA { @LocalStorageLink('localCount') localCount: number = 0 // ✅ @LocalStorageLink 双向绑定 LocalStorage 键 build() { Button(`ChildA count=${this.localCount}`) .onClick(() => { this.localCount++ }) // ✅ 改 → LocalStorage 同步 → 同页面 ChildB 同步 } } // LocalStorage 页面级局部状态:同页面多组件共享,页面卸载就销毁useState 魔法 vs 页面级状态存储槽的区别:React 把页面级状态当 useState 魔法(组件卸载 state 销毁),ArkTS 把 LocalStorage 当「页面级状态存储槽」(同页面多组件共享,页面卸载就销毁)。根因不是 useState 魔法是页面级状态存储槽——LocalStorage 页面级局部状态存储,同页面多组件共享,页面卸载就销毁。
二、根因:LocalStorage 的页面级状态存储槽机制
鸿蒙 ArkUI 的 LocalStorage 是页面级状态存储槽绑定——同页面多组件共享,页面卸载就销毁,来自三重绑定机制。
机制 1:LocalStorage 页面级局部状态存储——不是应用级 AppStorage
LocalStorage 荬饰器页面级局部状态存储——同页面多组件共享,页面卸载就销毁:
// ✅ 初始化 LocalStorage(页面级局部状态) interface LocalState { localCount: number; localTheme: string } const localStorage = new LocalStorage({ localCount: 0, localTheme: '#52C41A' } as LocalState) @Component struct ChildA { @LocalStorageLink('localCount') localCount: number = 0 // ✅ @LocalStorageLink 双向绑定 LocalStorage 键 build() { Column() { Text(`localCount = ${this.localCount}`) Button('改 localCount++') .onClick(() => { this.localCount++ }) // ✅ 改 → LocalStorage 同步 → 同页面 ChildB 同步 } } } // LocalStorage 页面级局部状态:同页面多组件共享,页面卸载就销毁(不跨页面共享)页面级局部状态存储:LocalStoragelocalCount页面级局部状态存储——同页面多组件共享localCount,页面卸载就销毁(不跨页面共享)。根因不是应用级 AppStorage 是页面级状态存储槽——LocalStorage 页面级局部状态存储,同页面多组件共享,页面卸载就销毁。
机制 2:@LocalStorageLink 双向绑定 LocalStorage 键——改 Storage 同页面同步
@LocalStorageLink 荬饰器双向绑定 LocalStorage 键——改 @LocalStorageLink → LocalStorage 同步 → 同页面其他组件同步:
@Component struct ChildA { @LocalStorageLink('localCount') localCount: number = 0 // ✅ @LocalStorageLink 双向绑定 LocalStorage 键 @LocalStorageLink('localTheme') localTheme: string = '#52C41A' build() { Column() { Text(`localCount = ${this.localCount}`).fontColor(this.localTheme) Button('改 localCount++') .onClick(() => { this.localCount++ }) // ✅ 改 → LocalStorage 同步 → 同页面 ChildB 同步 Button('改 localTheme=红色') .onClick(() => { this.localTheme = '#FF4D4F' }) // ✅ 改 → LocalStorage 同步 → 同页面 ChildB 同步 } } } // @LocalStorageLink 双向绑定 LocalStorage 键:改 → LocalStorage 同步 → 同页面其他组件同步双向@LocalStorageLink 双向绑定 LocalStorage 键:@LocalStorageLinklocalCount荬饰器双向绑定 LocalStorage 键——改localCount→ LocalStorage 同步 → 同页面其他组件同步双向。根因不是组件级 @State 是页面级状态存储槽——@LocalStorageLink 双向绑定 LocalStorage 键,改 → LocalStorage 同步 → 同页面其他组件同步双向。
机制 3:同页面多组件共享 LocalStorage——ChildA 改 ChildB 同步
LocalStorage同页面多组件共享——ChildA 改 LocalStorage 键 → 同页面 ChildB 同步(不用 props 透传):
@Component struct ChildA { @LocalStorageLink('localCount') localCount: number = 0 // ✅ ChildA 绑定 LocalStorage 键 build() { Button('ChildA 改 localCount++') .onClick(() => { this.localCount++ }) // ✅ ChildA 改 → LocalStorage 同步 → ChildB 同步 } } @Component struct ChildB { @LocalStorageLink('localCount') localCount: number = 0 // ✅ ChildB 也绑定同一 LocalStorage 键 build() { Text(`ChildB localCount = ${this.localCount}`) // ✅ ChildB 自动同步(不用 props 透传) } } // 同页面多组件共享 LocalStorage:ChildA 改 → ChildB 同步(不用 props 透传,同页面共享)同页面多组件共享 LocalStorage:LocalStoragelocalCount同页面多组件共享——ChildA 改localCount→ 同页面 ChildB 同步(不用 props 透传)。根因不是 props 透传是页面级状态存储槽——LocalStorage 同页面多组件共享,ChildA 改 → ChildB 同步(不用 props 透传)。
机制 4:LocalStorage vs AppStorage 应用级状态边界——页面级 vs 应用级
LocalStorage页面级局部状态(同页面多组件共享,页面卸载就销毁),AppStorage应用级全局状态(所有页面共享,页面卸载状态仍存在)——根因都是状态存储但绑的机制不同:
// ✅ LocalStorage 路径:页面级局部状态(同页面多组件共享,页面卸载就销毁) const localStorage = new LocalStorage({ localCount: 0 } as LocalState) @Component struct ChildA { @LocalStorageLink('localCount') localCount: number = 0 // ✅ @LocalStorageLink 双向绑定 LocalStorage 键 build() { Button(`ChildA ${this.localCount}`).onClick(() => { this.localCount++ }) } } @Component struct ChildB { @LocalStorageLink('localCount') localCount: number = 0 // ✅ 同页面 ChildB 也绑定 build() { Button(`ChildB ${this.localCount}`).onClick(() => { this.localCount++ }) } } // ✅ LocalStorage 页面级局部状态:ChildA 改 → ChildB 同步(同页面共享,页面卸载就销毁) // ⚠ AppStorage 路径:应用级全局状态(所有页面共享,页面卸载状态仍存在) AppStorage.setOrCreate('appCount', 0) @Entry @Component struct Page1 { @StorageLink('appCount') appCount: number = 0 // ⚠ @StorageLink 绑定 AppStorage 键(跨页面共享) build() { Button(`Page1 ${this.appCount}`).onClick(() => { this.appCount++ }) } } @Entry @Component struct Page2 { @StorageLink('appCount') appCount: number = 0 // ⚠ Page2 也绑定同一 AppStorage 键 build() { Button(`Page2 ${this.appCount}`).onClick(() => { this.appCount++ }) } } // ⚠ AppStorage 应用级全局状态:Page1 改 → Page2 同步(跨页面共享,页面卸载状态仍存在)LocalStorage vs AppStorage 应用级状态边界:LocalStorage 路径——页面级局部状态(同页面多组件共享,页面卸载就销毁,推荐单页面状态)。AppStorage 路径——应用级全局状态(所有页面共享,页面卸载状态仍存在,跨页面状态)。根因都是状态存储但绑的机制不同——LocalStorage 页面级状态存储槽(同页面共享),AppStorage 应用级状态存储槽(跨页面共享)。
三、真机配图:LocalStorage 页面级状态边界——同页面多组件共享
初始态(ChildA/B localCount=0、localTheme=“#52C41A” 绿色文字均页面级状态初始态齐):
点调三按钮后(ChildA localCount=11、ChildB localCount=11 同页面同步、localTheme=“#FF4D4F” 红色文字同步均同页面多组件共享证据齐):
对比证据:点 ChildA 改 localCount++ 后 ChildB localCount 同步(同页面多组件共享),点 ChildA 改 localTheme=红色后 ChildB localTheme 同步红字,点 ChildB 改 localCount+=10 后 ChildA localCount 同步(ChildB 改 ChildA 也同步双向)。LocalStorage 页面级局部状态——同页面多组件共享,页面卸载就销毁,@LocalStorageLink 双向绑定 LocalStorage 键,ChildA 改 ChildB 同步(不用 props 透传)。
四、真解法:LocalStorage 页面级状态的三个场景
场景 1:LocalStorage 同页面多组件计数器(90% 场景首选,页面级状态存储槽)
interface LocalState { localCount: number } const localStorage = new LocalStorage({ localCount: 0 } as LocalState) @Component struct ChildA { @LocalStorageLink('localCount') localCount: number = 0 // ✅ @LocalStorageLink 双向绑定 LocalStorage 键 build() { Column() { Text(`ChildA count = ${this.localCount}`) Button('ChildA 改 count++') .onClick(() => { this.localCount++ }) // ✅ 改 → LocalStorage 同步 → 同页面 ChildB 同步 } } } @Component struct ChildB { @LocalStorageLink('localCount') localCount: number = 0 // ✅ 同页面 ChildB 也绑定 build() { Text(`ChildB count = ${this.localCount}`) } // ✅ ChildB 自动同步(不用 props 透传) }为哈能跑:LocalStorage 同页面多组件计数器——页面级状态存储槽,LocalStoragelocalCount页面级局部状态+@LocalStorageLink 双向绑定 LocalStorage 键,ChildA 改localCount→ LocalStorage 同步 → 同页面 ChildB 同步双向。首选这个,90% 的场景同页面多组件状态共享用 LocalStorage 页面级状态存储槽就够。要写「同页面多组件状态共享(计数器等)」时用这个——不用 props 透传(冗余),LocalStorage 页面级状态存储槽同页面多组件共享。
场景 2:LocalStorage 同页面多组件主题色(页面级状态存储槽,同页面共享主题)
interface LocalState { localTheme: string } const localStorage = new LocalStorage({ localTheme: '#52C41A' } as LocalState) @Component struct ThemeA { @LocalStorageLink('localTheme') localTheme: string = '#52C41A' // ✅ @LocalStorageLink 绑定 build() { Column() { Text(`ThemeA theme = "${this.localTheme}"`).fontColor(this.localTheme) Button('ThemeA 改 theme=红色') .onClick(() => { this.localTheme = '#FF4D4F' }) // ✅ 改 → LocalStorage 同步 → 同页面 ThemeB 同步 } } } @Component struct ThemeB { @LocalStorageLink('localTheme') localTheme: string = '#52C41A' // ✅ 同页面 ThemeB 也绑定 build() { Text(`ThemeB theme = "${this.localTheme}"`).fontColor(this.localTheme) } // ✅ 自动同步 } // LocalStorage 同页面多组件主题色:ThemeA 改 → ThemeB 同步(同页面共享主题,不用 props 透传)为哈能跑:LocalStorage 同页面多组件主题色——页面级状态存储槽,LocalStoragelocalTheme页面级局部状态+@LocalStorageLink 双向绑定 LocalStorage 键,ThemeA 改localTheme→ LocalStorage 同步 → 同页面 ThemeB 同步双向。要写「同页面多组件主题共享(主题色等)」时用这个——不用 props 透传(冗余),LocalStorage 页面级状态存储槽同页面多组件共享主题。
场景 3:LocalStorage vs AppStorage 作用域边界(页面级 vs 应用级,选对存储槽)
// ✅ LocalStorage 页面级:同页面多组件共享,页面卸载就销毁(单页面状态用这个) const localStorage = new LocalStorage({ pageState: 0 } as LocalState) @Component struct PageComponent { @LocalStorageLink('pageState') pageState: number = 0 // ✅ 页面级(页面卸载就销毁) build() { Button(`页面级 ${this.pageState}`).onClick(() => { this.pageState++ }) } } // ✅ AppStorage 应用级:所有页面共享,页面卸载状态仍存在(跨页面状态用这个) AppStorage.setOrCreate('appState', 0) @Entry @Component struct CrossPage { @StorageLink('appState') appState: number = 0 // ✅ 应用级(跨页面共享,页面卸载状态仍存在) build() { Button(`应用级 ${this.appState}`).onClick(() => { this.appState++ }) } } // LocalStorage vs AppStorage 作用域边界:单页面状态用 LocalStorage(页面卸载就销毁) // 跨页面状态用 AppStorage(所有页面共享,页面卸载状态仍存在)为哈能跑:LocalStorage vs AppStorage 作用域边界——页面级状态用 LocalStorage(同页面多组件共享,页面卸载就销毁),应用级状态用 AppStorage(所有页面共享,页面卸载状态仍存在)。要写「选对状态存储槽(页面级 vs 应用级等)」时用这个——单页面状态用 LocalStorage(页面卸载就销毁),跨页面状态用 AppStorage(跨页面共享)。
五、一句话哲学
LocalStorage 不是应用级 AppStorage,是页面级局部状态存储槽的同页面多组件共享。ArkUI 的 LocalStorage 荬饰器页面级局部状态存储,同页面多组件共享,页面卸载就销毁。根因不是应用级 AppStorage 是页面级状态存储槽——LocalStorage 页面级局部状态存储(同页面多组件共享,页面卸载就销毁)+ @LocalStorageLink 双向绑定 LocalStorage 键(改 → LocalStorage 同步 → 同页面其他组件同步双向)+ 同页面多组件共享 LocalStorage(ChildA 改 ChildB 同步不用 props 透传)+ LocalStorage vs AppStorage 应用级状态边界(页面级 vs 应用级)。对比 React 页面级状态 useState 魔法(组件卸载 state 销毁),ArkTS LocalStorage 页面级状态存储槽同页面多组件共享。
状态联动深水区串讲:@Watch 绑 @State 变触发副作用回调槽(篇 68)+ @Link $ 语法双向绑定跨组件同步(篇 69)+ @Provide/@Consume 跨层级传递槽祖辈后辈同步(篇 70)+ @Observed/@ObjectLink 嵌套对象观测槽子属性改刷 UI(篇 71)+ AppStorage 应用级状态存储槽所有页面共享(篇 72)+ LocalStorage 页面级状态存储槽同页面多组件共享(篇 73,页面卸载就销毁)——续「ArkUI 状态联动」深水区,讲状态联动深水区(@Watch 副作用回调槽边界 + @Link $ 语法双向绑定边界 + @Provide/@Consume 跨层级传递槽边界 + @Observed/@ObjectLink 嵌套对象观测槽边界 + AppStorage 应用级状态存储槽边界 + LocalStorage 页面级状态存储槽边界)。
系列预告:下篇(篇 74)讲 @StorageLink/@StorageProp 应用级状态绑定边界(AppStorage 绑定根因),续「ArkUI 状态联动」深水区。五阶段哲学体系:类型哲学(50-52)→ 作用域哲学(53-55)→ 状态哲学(56-59)→ 渎染哲学(60-62)→ 组件设计(63-67)→ 状态联动深水区(68+)讲清 ArkTS/ArkUI 进阶哲学。
能力系列回链
| 能力系列篇 | 本文进阶点 |
|---|---|
| 篇 24 LocalStorage 用法 | LocalStorage 页面级状态存储槽边界根因(同页面多组件共享页面卸载就销毁) |
| 篇 23 AppStorage 用法 | 应用级状态存储槽边界(所有页面共享页面卸载状态仍存在) |
| 篇 59 @Watch 用法 | 状态联动深水区:@Watch 副作用回调槽 vs onClick 直接调副作用边界 |
真机 demo 完整代码
// 篇 73 demo:LocalStorage 页面级状态边界 // LocalStorage 页面级局部状态:同页面多组件共享,页面卸载销毁 // @LocalStorageLink/@LocalStorageProp 绑定 LocalStorage 键 // ✅ 初始化 LocalStorage(页面级局部状态) interface LocalState { localCount: number; localTheme: string } const localStorage = new LocalStorage({ localCount: 0, localTheme: '#52C41A' } as LocalState) // ✅ 子组件1:@LocalStorageLink 双向绑定 LocalStorage 键(页面级局部状态) @Component struct ChildA { @LocalStorageLink('localCount') localCount: number = 0 // ✅ @LocalStorageLink 双向绑定 @LocalStorageLink('localTheme') localTheme: string = '#52C41A' build() { Column({ space: 6 }) { Text('子组件 ChildA(@LocalStorageLink 双向绑定)') .fontSize(11).fontColor('#2563eb').fontWeight(FontWeight.Bold) Text(`localCount = ${this.localCount}`).fontSize(13).fontColor('#2563eb') Text(`localTheme = "${this.localTheme}"`).fontSize(11).fontColor(this.localTheme) Button('ChildA 改 localCount++(@LocalStorageLink 同页面同步)') .width('92%').height(36).fontSize(10) .onClick(() => { this.localCount++ }) // ✅ 改 → LocalStorage 同步 → ChildB 同步 Button('ChildA 改 localTheme=红色') .width('92%').height(36).fontSize(10) .onClick(() => { this.localTheme = '#FF4D4F' }) // ✅ 改 → LocalStorage 同步 → ChildB 同步 } .width('92%').padding(8).backgroundColor('#e0f0ff').borderRadius(6) } } // ✅ 子组件2:同页面另一组件也绑定 LocalStorage 键(同页面多组件共享) @Component struct ChildB { @LocalStorageLink('localCount') localCount: number = 0 // ✅ ChildB 也绑定同一 LocalStorage 键 @LocalStorageLink('localTheme') localTheme: string = '#52C41A' build() { Column({ space: 6 }) { Text('子组件 ChildB(同页面共享 LocalStorage)') .fontSize(11).fontColor('#ff6600').fontWeight(FontWeight.Bold) Text(`localCount = ${this.localCount}`).fontSize(13).fontColor('#ff6600') Text(`localTheme = "${this.localTheme}"`).fontSize(11).fontColor(this.localTheme) Button('ChildB 改 localCount+=10(@LocalStorageLink 同页面同步)') .width('92%').height(36).fontSize(10) .onClick(() => { this.localCount += 10 }) // ✅ ChildB 改 → ChildA 同步(同页面共享) } .width('92%').padding(8).backgroundColor('#fff0e0').borderRadius(6) } } @Entry @Component struct Index { build() { Column({ space: 12 }) { Text('篇 73 配图:LocalStorage 页面级状态边界') .fontSize(16).fontWeight(FontWeight.Bold).margin({ top: 16, bottom: 4 }) Text('LocalStorage 页面级局部状态:同页面多组件共享,页面卸载销毁(vs AppStorage 应用级跨页面共享)') .fontSize(10).fontColor('#888').margin({ bottom: 8 }) ChildA() ChildB() Text('同页面 ChildA 改 localCount → ChildB 同步(同页面多组件共享)') .fontSize(10).fontColor('#333').margin({ top: 8 }) Text('页面卸载 → LocalStorage 销毁(vs AppStorage 应用级页面卸载状态仍存在)') .fontSize(10).fontColor('#ff6600') } .width('100%').height('100%').alignItems(HorizontalAlign.Center) } }写鸿蒙 ArkUI 记住:LocalStorage 不是应用级 AppStorage 是页面级局部状态存储槽的同页面多组件共享——LocalStorage 荬饰器页面级局部状态存储,同页面多组件共享,页面卸载就销毁。根因不是应用级 AppStorage 是页面级状态存储槽——LocalStorage 页面级局部状态存储(同页面多组件共享,页面卸载就销毁)+ @LocalStorageLink 双向绑定 LocalStorage 键(改 → LocalStorage 同步 → 同页面其他组件同步双向)+ 同页面多组件共享 LocalStorage(ChildA 改 ChildB 同步不用 props 透传)+ LocalStorage vs AppStorage 应用级状态边界(页面级 vs 应用级)。LocalStorage 同页面多组件计数器用页面级状态存储槽(首选,90% 场景),LocalStorage 同页面多组件主题色用页面级状态存储槽同页面共享主题,LocalStorage vs AppStorage 作用域边界选对存储槽(单页面用 LocalStorage 页面卸载就销毁,跨页面用 AppStorage 跨页面共享)。页面级状态存储槽同页面多组件共享页面卸载就销毁是 ArkUI 状态联动深水区核心!