首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐
2025年6月7日 星期六 2:36am

鸿蒙ACE-V1状态分析LocalStorage

  • 24-12-10 09:06
  • 3845
  • 11846
juejin.cn

LocalStorage:页面级UI状态存储

developer.huawei.com/consumer/cn…

LocalStorage是页面级的UI状态存储,通过@Entry装饰器接收的参数可以在页面内共享同一个LocalStorage实例。LocalStorage支持UIAbility实例内多个页面间状态共享

@LocalStorageProp

@LocalStorageProp装饰的变量与LocalStorage中给定属性建立单向同步关系

@LocalStorageProp初始化规则图示

框架行为

  • 被@LocalStorageProp装饰的变量的值的变化不会同步回LocalStorage里。
  • @LocalStorageProp装饰的变量变化会使当前自定义组件中关联的组件刷新。
  • LocalStorage(key)中值的变化会引发所有被@LocalStorageProp对应key装饰的变量的变化,会覆盖@LocalStorageProp本地的改变。

@LocalStorageLink

@LocalStorageLink装饰的变量与LocalStorage中给定属性建立双向同步关系

@LocalStorageLink初始化规则图示

框架行为

  1. 当@LocalStorageLink(key)装饰的数值改变被观察到时,修改将被同步回LocalStorage对应属性键值key的属性中。
  2. LocalStorage中属性键值key对应的数据一旦改变,属性键值key绑定的所有的数据(包括双向@LocalStorageLink和单向@LocalStorageProp)都将同步修改。
  3. 当@LocalStorageLink(key)装饰的数据本身是状态变量,它的改变不仅仅会同步回LocalStorage中,还会引起所属的自定义组件的重新渲染。

转换前代码

js
代码解读
复制代码
/** * * LocalStorageCmpt.ets * Created by unravel on 2024/5/3 * @abstract */ import { StorageDemoClass } from './StateDemoPage' @Component export struct LocalStorageCmpt { // localstorage @LocalStorageProp('localStorageSimpleValueKey') localStoragePropSimpleValueVar: string = 'localStoragePropSimpleValueValue' @LocalStorageLink('localStorageObjectKey') localStorageLinkObjectVar: StorageDemoClass = new StorageDemoClass() aboutToAppear(): void { } build() { Column() { Text('localStoragePropSimpleValue: ' + this.localStoragePropSimpleValueVar) Text('localStorageLinkObject: ' + this.localStorageLinkObjectVar.name) }.onClick(() => { this.localStoragePropSimpleValueVar = 'cmpLocalStorageSimpleValue1' this.localStorageLinkObjectVar.name = 'cmpLocalStorageObject.name' }) } }

转换后代码

js
代码解读
复制代码
if (!("finalizeConstruction" in ViewPU.prototype)) { Reflect.set(ViewPU.prototype, "finalizeConstruction", () => { }); } interface LocalStorageCmpt_Params { localStoragePropSimpleValueVar?: string; localStorageLinkObjectVar?: StorageDemoClass; } import { StorageDemoClass } from "@bundle:com.unravel.myapplication/entry/ets/pages/StateDemoPage"; export class LocalStorageCmpt extends ViewPU { constructor(parent, params, __localStorage, elmtId = -1, paramsLambda = undefined, extraInfo) { super(parent, __localStorage, elmtId, extraInfo); if (typeof paramsLambda === "function") { this.paramsGenerator_ = paramsLambda; } this.setInitiallyProvidedValue(params); this.finalizeConstruction(); } setInitiallyProvidedValue(params: LocalStorageCmpt_Params) { } updateStateVars(params: LocalStorageCmpt_Params) { } purgeVariableDependenciesOnElmtId(rmElmtId) { this.__localStoragePropSimpleValueVar.purgeDependencyOnElmtId(rmElmtId); this.__localStorageLinkObjectVar.purgeDependencyOnElmtId(rmElmtId); } aboutToBeDeleted() { this.__localStoragePropSimpleValueVar.aboutToBeDeleted(); this.__localStorageLinkObjectVar.aboutToBeDeleted(); SubscriberManager.Get().delete(this.id__()); this.aboutToBeDeletedInternal(); } // localstorage private __localStoragePropSimpleValueVar: ObservedPropertyAbstractPU = this.createLocalStorageProp('localStorageSimpleValueKey', 'localStoragePropSimpleValueValue', "localStoragePropSimpleValueVar"); get localStoragePropSimpleValueVar() { return this.__localStoragePropSimpleValueVar.get(); } set localStoragePropSimpleValueVar(newValue: string) { this.__localStoragePropSimpleValueVar.set(newValue); } private __localStorageLinkObjectVar: ObservedPropertyAbstractPU<StorageDemoClass> = this.createLocalStorageLink<StorageDemoClass>('localStorageObjectKey', new StorageDemoClass(), "localStorageLinkObjectVar"); get localStorageLinkObjectVar() { return this.__localStorageLinkObjectVar.get(); } set localStorageLinkObjectVar(newValue: StorageDemoClass) { this.__localStorageLinkObjectVar.set(newValue); } aboutToAppear(): void { } initialRender() { this.observeComponentCreation2((elmtId, isInitialRender) => { Column.create(); Column.onClick(() => { this.localStoragePropSimpleValueVar = 'cmpLocalStorageSimpleValue1'; this.localStorageLinkObjectVar.name = 'cmpLocalStorageObject.name'; }); }, Column); this.observeComponentCreation2((elmtId, isInitialRender) => { Text.create('localStoragePropSimpleValue: ' + this.localStoragePropSimpleValueVar); }, Text); Text.pop(); this.observeComponentCreation2((elmtId, isInitialRender) => { Text.create('localStorageLinkObject: ' + this.localStorageLinkObjectVar.name); }, Text); Text.pop(); Column.pop(); } rerender() { this.updateDirtyElements(); } }

传递

这里我们的写法是显示的将storage传进了LocalStorageCmpt这个组件。

image.png

如果我们不显示传递,默认会传入一个undefined的storage

image.png

@LocalStorageProp

转换前后

转换成TS之后,和@State的操作类似。

  1. 将原有属性重写为getter和setter
  2. 声明一个以双下划线开头的类型为ObservedPropertyAbstractPU的私有属性,并通过this.createLocalStorageProp创建该属性值
  3. ObservedPropertyAbstractPU这个属性我们很熟悉了,它就是@State状态变量的数据源

image.png

ViewPU

public createLocalStorageProp(storagePropName: string, defaultValue: T, viewVariableName: string): ObservedPropertyAbstractPU

这个函数我们在鸿蒙ACE-ArkUI构建(二)、渲染控制和构建过程 提到过,这里再看下具体实现

我们看到这里是通过 this.localStorage_.__createSync 创建的

image.png

localStorage_是getter、setter

我们看下localStorage_从哪里来的。可以看到localStorage_实际上是getter和setter,真正存储的是 localStoragebackStore_

image.png

localStoragebackStore_ 实际存储storage

组件初始化的时候如果传递了storage,则将传递过来的storage赋值给 localStoragebackStore_

image.png

public get localStorage_(): LocalStorage

localStorage_会递归往父组件找,如果没找到会创建一个默认的storage。

这一块的逻辑和Provide很相似,可以回忆一下Provide是怎么查找对应key的状态变量的

image.png

LocalStorage

public __createSync(storagePropName: string, defaultValue: T, factoryFunc: SynchedPropertyFactoryFunc): ObservedPropertyAbstract

先通过storage_根据属性名称取值,没有值的话会通过addNewPropertyInternal创建一个新的属性p,然后将p作为参数调用factoryFunc

image.png

storage_ 是一个Map

这个storage_ 实际上是一个map,用于按属性名存储ObservedPropertyAbstract实例

image.png

private addNewPropertyInternal(propName: string, value: T): ObservedPropertyAbstract

这个函数实际创建ObservedPropertyAbstract实例并存储到map中,最终将创建的ObservedPropertyAbstract实例返回

image.png

factoryFunc

factoryFun就是我们传入的闭包函数,它的最终实现其实是创建了一个SynchedPropertyObjectOneWay的单向同步实例

image.png

小结

  1. 每个组件都是一个ViewPU,在ViewPU内部有一个localStorageStore_ 属性,用于存储localStorage实例。
  2. localStorage实例实际上是getter和setter,并不实际存储storage的值。实际存储storage的类是 localStoragebackStore_
  3. 如果从父组件传递了storage过来,就是用传递过来的storage,否则会从父组件开始递归查找,如果最终没有找到storage,则创建一个默认的storage
  4. @LocalStorageProp转换后是一个类型为SynchedPropertyObjectOneWay的单向同步实例
  5. 可以看到@LocalStorageProp和@Prop很类似,除了多了一个查找storage中对应key的状态变量的过程

get、set

可以看到@LocalStorageProp装饰的变量的setter和getter实际上是操作的ObservedPropertyAbstract的get和set方法

ObservedPropertyAbstract是@State状态包装类的父类,所以这里的get和set也和@State的一样(关联UI、UI刷新等) 鸿蒙ACE-V1状态分析@Prop

image.png

storage.setOrCreate('key',value) 怎么驱动UI更新?

LocalStorage

public setOrCreate(propName: string, newValue: T): boolean

上面我们看的是@LocalStorageProp状态变量关联和驱动UI的逻辑。那么storage.setOrCreate('key',value)方法设置key的值之后,UI为什么会更新呢?

setOrCreate先取出key键关联的对象,然后调用了对象的set方法,后面就和@State状态变量更新导致@Prop更新一样了,可以参考 鸿蒙ACE-V1状态分析@Prop

image.png

storage.prop('key').set(222)又是怎么驱动UI更新?

LocalStorage

public prop(propName: string, propUser?: IPropertySubscriber, subscribersName?: string): SubscribedAbstractProperty | undefined

storage.prop('key') 和 @LocalStorageProp 实现几乎一样,都是返回的一个SynchedPropertyOneWayPU,这个对象会跟随ObservedPropertyPU的set方法一起更新

image.png

@LocalStorageLink

转换前后

转换成TS之后,和@State的操作类似。

  1. 将原有属性重写为getter和setter
  2. 声明一个以双下划线开头的类型为ObservedPropertyAbstractPU的私有属性,并通过this.createLocalLink创建该属性值

image.png

ViewPU

public createLocalStorageLink(storagePropName: string, defaultValue: T, viewVariableName: string): ObservedPropertyAbstractPU

这个过程和createLocalStorageProp的过程非常相似,唯一的区别是factoryFunc的实现

createLocalStorageProp是创建一个 SynchedPropertyObjectOneWayPU。看到这个类你应该想起了@Prop

而createLocalStorageLink是创建一个 SynchedPropertyTwoWayPU。看到这个类你应该想起了@Link

image.png

一旦找到对应key的状态类实例,就和@Link的操作是一样的了。因为所有的API都是先通过key拿到key对应的状态实例,然后进行操作

小结

  1. @LocalStorageLink的创建过程和@LocalStorageProp的创建过程非常类似,只是factoryFun不一样
  2. @LocalStorageProp和@LocalStorageLink与@Prop和@Link几乎一样,只不多过了一个查找对应key状态变量的过程。而这个key存储的就是类是和@Prop或@Link底层包装类是一样的

总结

  1. storage里面有一个Map用于存储键值对应的状态变量,可以理解为一个key对应一个@State,而@LocalStorageProp则相当于@Prop,@LocalStorageLink相当于@Link
  2. 可以把storage理解每个key对应一个@State的map,是一个集合
注:本文转载自juejin.cn的HarderCoder的文章"https://juejin.cn/post/7418118910413062154"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

141
iOS
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top