鸿蒙ACE-V1状态分析LocalStorage

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中,还会引起所属的自定义组件的重新渲染。

转换前代码


import { StorageDemoClass } from './StateDemoPage'
 
 
@Component
export struct LocalStorageCmpt {
  
  @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'
    })
  }
}

转换后代码

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();
    }
    
    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,是一个集合
阅读全文
下载说明:
1、本站所有资源均从互联网上收集整理而来,仅供学习交流之用,因此不包含技术服务请大家谅解!
2、本站不提供任何实质性的付费和支付资源,所有需要积分下载的资源均为网站运营赞助费用或者线下劳务费用!
3、本站所有资源仅用于学习及研究使用,您必须在下载后的24小时内删除所下载资源,切勿用于商业用途,否则由此引发的法律纠纷及连带责任本站和发布者概不承担!
4、本站站内提供的所有可下载资源,本站保证未做任何负面改动(不包含修复bug和完善功能等正面优化或二次开发),但本站不保证资源的准确性、安全性和完整性,用户下载后自行斟酌,我们以交流学习为目的,并不是所有的源码都100%无错或无bug!如有链接无法下载、失效或广告,请联系客服处理!
5、本站资源除标明原创外均来自网络整理,版权归原作者或本站特约原创作者所有,如侵犯到您的合法权益,请立即告知本站,本站将及时予与删除并致以最深的歉意!
6、如果您也有好的资源或教程,您可以投稿发布,成功分享后有站币奖励和额外收入!
7、如果您喜欢该资源,请支持官方正版资源,以得到更好的正版服务!
8、请您认真阅读上述内容,注册本站用户或下载本站资源即您同意上述内容!
原文链接:https://www.shuli.cc/?p=20817,转载请注明出处。
0

评论0

显示验证码
没有账号?注册  忘记密码?