在声明式 UI 框架中,数据的改变触发 UI 的重新渲染。在 ArkUI 中不是所有数据的变化都会触发 UI 重新渲染,只有 状态变量 才会引起 UI 重新渲染。
状态变量
状态变量: 指被状态装饰器装饰的变量,只有这种变量的改变才会引起 UI 的重新渲染。
常规变量: 指没有被状态装饰器装饰的变量,不会引起 UI 的重新渲染。
按影响范围分为:
- 组件级别的状态: @State, @Prop, @Link, @Provide/@Consume, @Observed, @ObjectLink
- 应用级别的状态:@StorageLink/@LocalStorageLink, @StorageProp/@LocalStorageProp
按传递方向分为:
- 只读的单向传递
- 可变更的双向传递
@State 组件内状态
@State 装饰的状态变量,是组件内的状态,是私有的,只能从组件内部访问,不与父组件中任何类型的状态变量同步。
允许装饰的变量类型:Object、class、string、number、boolean、enum,Date, 以及这些类型的数组。API11及以上支持Map、Set, undefined,null 和 联合类型
@State 装饰原始类型
1 | typescript复制代码@Entry |
点击 Button 修改了 text,count 变量的值,会触发 UI 重新渲染,显示最新的值。
@State 装饰 class
1 | typescript复制代码export class User { |
1 | typescript复制代码@Entry |
对于 @State 装饰的 Class 状态变量, ArkUI 只能观察到状态变量的一级属性的变化,从而引起 UI 重新渲染。如上例中 user.name 和 user.car 是 User 的一级属性,user.car.brand 是 User 的二级属性, 所以点击Button执行 this.user.car.brand = 'BMW'
UI 没有刷新,这种情况,需要使用 @Observed/@ObjectLink
@State 装饰数组
1 | typescript复制代码@Entry |
对于数组,ArkUI 可以观察到 数组新增,删除,重新创建数组, 数组项重新赋值,从而引起 UI 重新渲染,无法观察到 数组中某个元素的 属性的变化
@Prop 父 —> 子单向同步
@Prop 是单向同步的:对父组件状态变量值的修改,将同步给子组件@Prop装饰的变量,子组件@Prop变量的修改不会同步到父组件的状态变量上。
1 | typescript复制代码@Entry |
@Prop 装饰的状态变量, ArkUI 同样观察不到 二级属性的变化,并且子组件状态变量的变化不会引起父组件 UI 的刷新, 但父组件状态变量的变化可以引起子组件的刷新。
@Link 父子双向同步
子组件中被@Link装饰的变量与其父组件中对应的数据源建立双向数据绑定.
@Link装饰器不能在@Entry装饰的自定义组件中使用。
@Link 装饰原始类型
1 | typescript复制代码@Entry |
父子组件的状态变量的变化,可以相互引起 UI 刷新
@Link 装饰 class
1 | typescript复制代码@Entry |
@Link 装饰的状态变量, ArkUI 同样观察不到 二级属性的变化。一级属性可以引起父子组件UI 的刷新。
@Link 装饰数组
1 | typescript复制代码@Entry |
@Provide/@Consume 父与后代组件双向同步
@Provide和@Consume,应用于与后代组件的双向数据同步,应用于状态数据在多个层级之间传递的场景。不同于上文提到的父子组件之间通过命名参数机制传递,@Provide和@Consume摆脱参数传递机制的束缚,实现跨层级传递。
@Provide/@Consume 装饰原始类型
1 | typescript复制代码@Entry |
@Provide/@Consume 装饰 class
1 | typescript复制代码@Entry |
@Oberved/@ObjectLink 嵌套类对象属性变化
上述 @State, @Prop,@Link 和 @Provide/@Consume 装饰器只能观察 class 一级属性赋值,无法观察二级属性变化,但在实际开发过程中,class 的属性类型仍是 class 类型是很常用见的,因此就需要使用 @Observed/@ObjectLink 来实现了。
@ObjectLink和@Observed类装饰器用于在涉及嵌套对象或数组的场景中进行双向数据同步:
- 被@Observed装饰的类,可以被观察到属性的变化;
- 子组件中@ObjectLink装饰器装饰的状态变量用于接收@Observed装饰的类的实例,和父组件中对应的状态变量建立双向数据绑定。这个实例可以是数组中的被@Observed装饰的项,或者是class object中的属性,这个属性同样也需要被@Observed装饰。
- 单独使用@Observed是没有任何作用的,需要搭配@ObjectLink或者@Prop使用。
- @ObjectLink 装饰的变量必须为被@Observed装饰的class实例
- @ObjectLink 装饰的变量不允许重新赋值。
@ObjectLink 装饰 class
1 | typescript复制代码@Entry |
@ObjectLink 装饰数组中数组项
1 | typescript复制代码@Entry |
ViewModel 存储数据
1 | typescript复制代码@Entry |
@ObservedV2装饰器和@Trace装饰器:类属性变化观测
从 API12 开始,更推荐使用@ObservedV2装饰器和@Trace装饰器装饰类以及类中的属性,来管理状态。
1 | typescript复制代码@ObservedV2 |
本文转载自: 掘金