在构建页面多为静态界面,如果希望构建一个动态的,有交互的界面,就需要引入‘状态’的概念。
一.基本概念
1.状态变量:被状态装饰器装饰的变量,状态变量值的改变或引起UI的渲染更新
2.常规变量:没有被状态装饰器装饰的变量,通常应用于辅助计算。它的改变永远不会引起UI的刷新。
3.数据源/同步源:状态变量的原始来源,可以同步给不同的状态数据。通常意义为父组件传给子组件的数据。
4.命名参数机制:父组件通过指定参数传递给子组件的状态变量,为父子传递同步参数的主要手段。
5.从父组件初始化:父组件使用命名参数机制,将指定参数传递给子组件。子组件初始化的默认值在有父组件传值的情况下,会被覆盖。
6.初始化子组件:父组件中状态变量可以传递给子组件,初始化子组件对应的状态变量。
7.本地初始化:在变量声明的时候赋值,作为变量的默认值。
说明:
当前状态管理的功能仅支持在UI主线程使用,不能在子线程、worker、taskpool中使用。
二.装饰器分类
状态变量不仅可以观察在组件内的改变,还可以在不同组件层级间传递,比如父子组件、跨组件层级,也可以观察全局 范围内的变化。根据状态变量的影响范围,将所有的装饰器可以大致分为:
管理组件内状态的装饰器:组件级别的状态管理,可以观察同一个组件树上(即同一个页面内)组件内或不同组件层级的变量变化。
管理应用级状态的装饰器:应用级别的状态管理,可以观察不同页面,甚至不同UIAbility的状态变化,是应用内全局的状态变量。
从数据的传递形式和同步类型层面看,装饰器也可分为:1.只读的单向传递 2.可变更的双向传递。
1.管理组件内状态的装饰器
(1) @State:组件内状态
@State装饰的变量拥有其所属组件的状态,可以作为其子组件的单向和双向同步的数据源。当其数值改变时,会引起相关组件的渲染刷新。
@State装饰的变量,或成为状态变量,一旦变量拥有了状态属性,就可以触发其直接绑定UI组件的刷新。当状态改变时,UI会发生对应的渲染改变。
在状态变量相关装饰器中,@State是最基础的,使变量拥有状态属性的装饰器,它也是大部分状态变量的数据源。
1.@State概述
@State装饰的变量,与声明式范式中的其他被装饰变量一样,是私有的,只能从组件内部访问,在声明时必须指定其类型和本地初始化。初始化也可以选择使用命名参数机制从父组件完成初始化。
2.@State装饰的变量的特点
(1)@State装饰的变量与子组件中的@Prop装饰变量之间建立单向数据同步,与@Link、@ObjectLink装饰变量之间建立双向数据同步
(2)@State装饰的变量生命周期与其所属自定义组件的生命周期相同
3.@State装饰器使用规则说明
@State变量装饰器 | 说明 |
装饰器参数 | 无 |
同步类型 | 不与父组件中任何类型的变量同步 |
允许装饰的变量类型 | Object、class、string、number、boolean、enum、Date、Map、Set、undefined、null类型。以及这些类型的数组 支持ArkUI框架定义的联合类型Length、ResourceStr、ResourceColor类型。类型必须被指定, 当使用undefined和null的时候,建议显式指定类型,遵循TypeScript类型校验 比如:@State a : string | undefined = undefined是推荐的 不支持any |
被装饰变量的初始值 | 必须本地初始化 |
4.变量的传递/访问规则说明
传递/访问 | 说明 |
从父组件初始化 | 可选,从父组件初始化或者本地初始化。如果从父组件初始化,并且从父组件传入的值非undefined,将会覆盖本地初始化;如果从父组件传入的值为undefined,则初值为@State装饰变量自身的初值。 支持父组件中的常规变量(常规变量对@State赋值,只是数值的初始化,常规变量的变化不会触发UI刷新,只有状态变量才能触发UI刷新)、@State、@Link、@Prop、@Provied、@Consume、@ObjectLink、@StorageLink、@StorageProp、@LocalStorageLink和@LocalStorageProp装饰的变量,初始化子组件的@State |
用于初始化子组件 | @State装饰的变量支持初始化子组件的常规变量、@State、@Link、@Prop、@Provide |
是否支持组件外访问 | 不支持,只能在组件内访问 |
5.观察变化和行为表现
- 当装饰的数据类型为boolean、string、number类型时,可以观察到数值的变化
- 当装饰的数据类型为class或者Object时,可以观察到自身的赋值的变化和其属性赋值的变化,嵌套属性的赋值观察不到。
- 当装饰的对象是array时,可以观察到数组本身的赋值的添加、删除、更新数组的变化。数组项中属性的赋值观察不到
- 当装饰的对象是Date时,可以观察到Date整体的赋值,同时可通过调用Date的接口setFullYear,setMonth, setDate, setHours, setMinutes, setSeconds, setMilliseconds, setTime, setUTCFullYear, setUTCMonth, setUTCDate, setUTCHours, setUTCMinutes, setUTCSecinds, setUTCMilliseconds更新Date的属性。
- 当装饰的变量时Map时,可以观察到Map整体的赋值,同时可通过调用Map接口set,clear,delete更新Map的值
- 当装饰的变量是Set时,可以观察到Set整体的赋值,同时可通过调用Set的接口add,clear,delete更新Set的值。
6.常见问题
(1)使用箭头函数改变状态变量未生效
箭头函数体内的this对象,就是定义该函数时所在的作用域指向的对象,而不是使用时所在的作用域指向的对象。
(2)状态变量的修改放在构造函数内未生效
在状态管理中,类会被一层‘代理’进行包装。当在组件中改变该类的成员变量时,会被该代理进行拦截。在更改数据源中值的同时,也会将变化通知给绑定的组件,从而实现观测变化与触发刷新。
(3)状态变量只能影响其直接绑定的UI组件的刷新
(4)复杂类型常量重复赋值给状态变量触发刷新
(5)不允许在build里改状态变量
不允许在build里改变状态变量,状态管理框架会在运行时报出Error级别日志。
(6)使用a.b(this.object)形式调用,不会触发UI刷新
在build方法内,当@State装饰的变量是Object类型,且通过a.b(this.object)形式调用时,b方法内传入的是this.object的原生对象,修改其属性,无法触发UI刷新。可以通过 先赋值,再调用新赋值的变量的方法,实现UI刷新。
(7)自定义组件外改变状态变量
开发者可以在aboutToAppear中注册箭头函数,并以此来改变组件中的状态变量。但需要注意的是在aboutToDisappear中将之前注册的函数置空,否则会因为箭头函数捕获了自定义组件的this实例,导致自定义组件无法被释放,从而造成内存泄漏。
(2) @Prop:父子单向同步
@Prop装饰的变量可以和父组件建立单向同步关系,@Prop装饰的变量是可变的 ,但修改不会同步回父组件。
1. @Prop概述
@Prop装饰的变量和父组件建立单向的同步关系:
- @Prop变量允许在本地修改,但修改后的变化不会同步回父组件。
- 当数据源更改时,@Prop装饰的变量都会更新,并且会覆盖本地所有更改。因此,数值的同步是父组件到子组件(所属组件),子组件数值的变化不会同步到父组件。
2.@Prop限制条件
@Prop装饰变量时会进行深拷贝,在拷贝的过程中除了基本类型、Map、Set、Date、Array外,都会丢失类型。例如PixelMap等通过NAPI提供的复杂类型,由于有部分实现在Native侧,因此无法在ArkTS侧通过深拷贝获得完整的数据。
@Prop装饰器不能在@Entry装饰的自定义组件中使用。
3.装饰器使用规则说明
@Prop变量装饰器 | 说明 |
装饰器参数 | 无 |
同步类型 | 单向同步:对父组件状态变量值的修改,将同步给子组件@Prop装饰的变量,子组件@Prop变量的修改不会同步到父组件的状态变量上。 |
允许装饰的变量类型 | Object、class、string、number、boolean、enum、Date、Map、Set、undefined、null类型。以及这些类型的数组 支持ArkUI框架定义的联合类型Length、ResourceStr、ResourceColor类型。类型必须被指定。 @Prop装饰的变量和@State以及其他装饰器同步时双方的类型必须相同 @Prop装饰的变量和@State以及其他装饰器装饰的数组的项同步时,@Prop的类型需要和@State装饰的数组的数组项相同 当父组件状态变量为Object或者class时,@Prop装饰的变量和父组件状态变量的属性类型相同 |
嵌套传递层数 | 在组件复用场景,建议@Prop深度嵌套数据不要超过5层,嵌套太多会导致深拷贝占用的空间过大以及GarbageCollection(垃圾回收)引发性能问题,此时更建议使用@ObjectLink |
被装饰变量的初始值 | 允许本地初始化 |
4.变量的传递/访问规则说明
传递/访问 | 说明 |
cc | 如果本地有初始化,则是可选的,初始化行为和@State保持一致。没有的话,则必选,支持父组件中的常规变量(常规变量对@Prop赋值,只能数值的初始化,常规变量的变化不会触发UI刷新。只有状态变量才能触发UI刷新)、@State、@Link、@Prop、@Provied、@Consume、@ObjectLink、@StorageLink、@StorageProp、@LocalStorageLink和@LocalStorageProp去初始化子组件中的@Prop变量 |
用于初始化子组件 | @Prop支持去初始化子组件中的常规变量、@Satte、@Link、@Prop、@Provide |
是否支持组件外访问 | @Prop装饰的变量是私有的,只能在组件内访问。 |
5.观察变化和行为表现
@Prop装饰的数据可以观察到以下变化
(1)当装饰的类型是允许的类型,即Object、class、string、number、boolean、enum类型都可以观察到赋值的变化。
(2)当装饰的类型是Object或者class复杂类型时,可以观察到第一层的属性的变化,属性即Object.keys(observedObject)返回的所有属性,观察不到第二层的变化
对于嵌套场景,如果class是被@Observed装饰的,可以观察到class属性的变化
(3)当装饰的类型是数组的时候,可以观察到数组本身的赋值和数组项的添加、删除和更新。
(4)对于@State和@Prop的同步场景:
- 使用父组件中@State变量的值初始化子组件中的@Prop变量。当@State变量变化时,该变量值也会同步更新至@Prop变量。
- @Prop装饰的变量的修改不会影响其数据源@State装饰变量的值。
- 除了@State,数据源也可以用@Link或@Prop装饰,对@Prop的同步机制是相同的。
- 数据源和@Prop变量的类型需要相同,@Prop允许简单类型和class类型
- 当装饰的对象是Date时,可以观察到Date整体的赋值,同时可通过调用Date的接口setFullYear,setMonth, setDate, setHours, setMinutes, setSeconds, setMilliseconds, setTime, setUTCFullYear, setUTCMonth, setUTCDate, setUTCHours, setUTCMinutes, setUTCSecinds, setUTCMilliseconds更新Date的属性。
- 当装饰的变量时Map时,可以观察到Map整体的赋值,同时可通过调用Map接口set,clear,delete更新Map的值
- 当装饰的变量是Set时,可以观察到Set整体的赋值,同时可通过调用Set的接口add,clear,delete更新Set的值。
6.框架行为
要理解@Prop变量值初始化和更新机制,有必要了解父组件和拥有@Prop变量的子组件初始渲染和更新流程。
1.初始渲染:
a.执行父组件的build()函数将创建子组件的新实例,将数据源传递给子组件
b.初始化子组件@Prop装饰的变量
2.更新:
a.子组件@Prop更新时,更新仅停留在当前子组件,不会同步回父组件。
b.当父组件的数据源更新时,子组件的@Prop装饰的变量将被来自父组件的数据源重置,所有@Prop装饰的本地的修改将被父组件的更新覆盖。
说明:1.@Prop装饰的数据更新依赖其所属自定义组件的重新渲染,所以在应用进入后台后,@Prop无法刷新,推荐使用@Link代替。
7.使用场景
(1)父组件@State到子组件@Prop简单数据类型同步
(2)父组件@State数组项到子组件@Prop简单数据类型同步
(3)从父组件中的@State类对象属性到@Prop简单类型的同步
(4)从父组件中的@State数组项到@Prop class类型的同步
@State装饰器只能观察到第一层属性,不会观察到此属性更改,所以框架不会更新,需要使用@Observed装饰class Book, Book的属性将被观察,需要注意的是,@Prop在子组件装饰的状态变量和父组件的数据源是单向同步关系。而父组件只会在数值有更新的时候(和上一次状态的对比),才会触发UI的重新渲染。@Observed装饰的类的实例会被不透明的代理对象包装,此代理可以检测到包装对象内的所有属性更改。如果发生这种情况,此时,代理通知@Prop,@Prop对象值被更新。
(5)Prop本地初始化不和父组件同步
为了支持@Component装饰的组件复用场景,@Prop支持本地初始化,这样可以让@Prop是否与父组件建立同步关系变得可选,当且仅当@Prop有本地初始化时,从父组件向子组件传递@Prop的数据源才是可选的。
(6)Prop嵌套场景
再嵌套场景下,每一层都要用@Observed装饰,且每一层都要被@Prop接受,这样才能观察到嵌套场景。
(7)Prop支持联合类型
8.常见问题
(1)@Prop装饰状态变量未初始化错误
@Prop需要被初始化,如果没有进行本地初始化的,则必须通过父组件进行初始化。如果进行了本地初始化,那么是可以不通过父组件进行初始化的。
(2)使用a.b(this.object)形式带哦用,不会触发UI刷新
在build方法内,当@Prop装饰的变量是Object类型,且通过a.b(this.object)形式调用时,b方法内传入的是this.object的原生对象,修改其属性,无法触发UI刷新。可以通过如下先赋值、再调用新赋值的变量的方式实现UI刷新
(3)@Link:父子双向同步
@Link装饰的变量可以和父组件建立双向同步关系,子组件中@Link装饰变量的修改会同步给父组件中建立双向数据绑定的数据源,父组件的更新也会同步给@Link装饰的变量。
1.@Link概述
@Link装饰的变量与其父组件中的数据源共享相同的值。
2.装饰器使用规则说明
@Link变量装饰器 | 说明 |
装饰器参数 | 无 |
同步类型 | 双向同步 父组件中的状态变量可以与子组件@Link建立双向同步,当其中一方改变时,另外一方能够感知到变化。 |
允许装饰的变量类型 | Object、class、string、number、boolean、enum、Date、Map、Set、undefined、null类型。以及这些类型的数组 支持ArkUI框架定义的联合类型Length、ResourceStr、ResourceColor类型。类型必须被指定。且和双向绑定状态变量的类型相同 不支持any |
被装饰变量的初始值 | 无,禁止本地初始化 |
3.变量的传递/访问规则说明
传递/访问 | 说明 |
从父组件初始化和更新 | 必选。与父组件@State,@StorageLink和@Link建立双向绑定。允许父组件中@State、@Link、@Prop、@Provied、@Consume、@ObjectLink、@StorageLink、@StorageProp、@LocalStorageLink和@LocalStorageProp装饰变量初始化子组件@Link。 |
用于初始化子组件 | 允许,可用于初始化常规变量、@State、@Link、@Prop、@Provide |
是否支持组件外访问 | 私有,只能在所属组件内访问。 |
4.框架行为
@Link装饰的变量和其所属的自定义组件共享生命周期。
为了了解@Link变量初始化和更新机制,有必要先了解父组件和拥有@Link变量的子组件的关系,初始渲染和双向更新的流程(以父组件为@State为例)
1.初始渲染:执行父组件的build()函数后将创建子组件的新实例。初始化过程如下:
- 必须指定父组件中的@State变量,用于初始化子组件的@Link变量。子组件的@Link变量值与其父组件的数据源变量保持同步(双向数据同步)
- 父组件的@State状态变量包装类通过构造函数传给子组件,子组件的@Link包装类拿到父组件的@State的状态变量后,将当前的@Link包装类this指定注册给父组件的@State变量。
2.@Link的数据源的更新:即父组件中的状态变量更新,引起相关子组件的@Link的更新。处理步骤:
- 通过初始渲染的步骤可知,子组件@Link包装类把当前this指针注册给父子间。父组件@State变量变更后,会遍历更新所有依赖它的系统组件(elementid)和状态变量(比如@Link包装类)
- 通知@Link包装类更新后,子组件中所有依赖@Link状态变量的系统组件(elementld)都会被通知更新。以此实现父组件对子组件的状态数据同步。
3.@Link的更新:当子组件中@Link更新后,处理步骤如下(以父组件为@State为例):
- @Link更新后,调用父组件的@State包装类的set方法,将更新后的数值同步回父组件。
- 子组件@Link和父组件@State分别遍历依赖的系统组件,进行对应的UI的更新。以此实现子组件@Link同步回父组件@State
5.限制条件
(1)@Link装饰器不能再@Entry装饰的自定义组件中使用。
(2)@Link装饰的变量禁止本地初始化,否则编译期会报错
(3)@Link装饰的变量的类型要和数据源类型保持一致,否则框架会抛出运行时错误。
(4)@Link装饰的变量仅能被状态变量初始化,不能用常量初始化,编译器会有warn告警,运行时会抛出is not callable 运行时错误
(5)@Link不支持装饰Function类型的变量,框架会抛出运行时错误。
6.常见问题
(1)@Link装饰状态变量类型错误
在子组件中使用@Link装饰状态变量需要保证该变量与数据源类型完全相同,且该数据源需为被诸如@State等装饰器装饰的状态变量。简而言之,@Link装饰的数据必须和数据源类型相同
(2)使用a.b(this.object)形式调用,不会触发UI刷新
在build方法内,当@Link装饰的变量是Object类型、且通过a.b(this.ibject)形式调用时,b方法内传入的是this.object的原生对象,修改其属性,无法触发UI刷新。可以通过先赋值,在调用新赋值的变量方法,实现UI刷新。
(3)@State放在build后定义时初始化@Link报错
当@State变量放在build函数后定义,用来初始化@Link变量时,会被识别为常量,而@Link变量不能被常量初始化,所以会造成编译报错。正确写法:可以把@State变量放在build函数前定义
(4)@Provide/@Consume:后代组件双向同步
@Provide/@Consume装饰的变量用于跨组件层级(多层组件)同步状态变量,可以不需要通过参数名机制传递,通过alias(别名)或者属性名绑定。
@Provide和@Consume,应用于与后代组件的双向数据同步,应用于状态数据在多个层级之间传递的场景。不同于上文提到的父子组件之间通过命名参数机制传递,@Provide和@Consume摆脱了传参机制的束缚,实现跨层级传递。
其中@Provide装饰的变量是在祖先组件中,可以理解为被‘提供’给后代的状态变量。@Consume装饰的变量是在后代组件中,去‘消费(绑定)’祖先组件提供的变量
@Provide/@Consume是跨组件层级的双向同步。
1.概述
@Provide/@Consume装饰的状态变量有以下特性:
- @Provide装饰的状态变量自动对其所有后代组件可用,即该变量被‘Provide’给他的后代组件。由此可见,@Provide的方便之处在于,开发者不需要多次在组件之间传递变量。
- 后代通过使用@Consume去获取@Provide提供的变量,建立在@Provide和@Consume之间的双向数据同步,与@State/@Link不同的是,前者可以在多层级的父子组件之间传递
- @Provide和@Consume可以通过相同的变量名或者相同的变量别名绑定,建议类型相同,否者会发生类型隐式转换,从而导致应用行为异常。
@Provide和@Consume通过相同的变量名或者相同的变量别名绑定时,@Provide装饰的变量和@Consume装饰的变量是一对多的关系。不允许在同一个自定义组件内,包括其子组件中声明多个同名或者同别名的@Provide装饰的变量,@Provide的属性名或别名需要唯一且确定,如果声明多个同名或者同别名的@Provide装饰的变量,会发生运行时报错。
2.装饰器说明
@Provide变量装饰器 | 说明 |
装饰器参数 | 别名:常量字符串,可选。如果指定了别名,则通过别名来绑定变量;如果未指定别名,则通过变量名绑定变量 |
同步类型 | 双向同步 从@Provide变量到所有@consume变量以及相反的方向的数据同步。双向同步的操作与@State和@Link的组合相同。 |
允许装饰的变量类型 | Object、class、string、number、boolean、enum、Date、Map、Set、undefined、null类型。以及这些类型的数组 支持ArkUI框架定义的联合类型Length、ResourceStr、ResourceColor类型。类型必须被指定。 @Provide变量的@Consume变量的类型必须相同 不支持any |
被装饰变量的初始值 | 必须指定 |
支持allowOverride参数 | 允许重写,只要声明了allow Override,则别名和属性名都可以被Override |
@Consume变量装饰器 | 说明 |
装饰器参数 | 别名:常量字符串,可选。如果指定了别名,则必须有@Provide的变量和其有相同的别名才可以匹配成功;否则,则需要变量名相同才能匹配成功 |
同步类型 | 双向从@Provide变量到所有@consume变量以及相反的方向的数据同步。双向同步的操作与@State和@Link的组合相同。 |
允许装饰的变量类型 | Object、class、string、number、boolean、enum、Date、Map、Set、undefined、null类型。以及这些类型的数组 支持ArkUI框架定义的联合类型Length、ResourceStr、ResourceColor类型。类型必须被指定。 @Provide变量的@Consume变量的类型必须相同 @Consume装饰的变量,在其父组件或者祖先组件上,必须有对应的属性和别名的@Provide装饰的变量 不支持any |
被装饰变量的初始值 | 无,禁止本地初始化 |
3.变量的传递/访问规则说明
@Provide传递/访问 | 说明 |
从父组件初始化和更新 | 可选,允许父组件中常规变量(常规变量对@Provide赋值,只是数值的初始化,常规变量的变化不会触发UI刷新,只有状态变量才能触发UI刷新)@State、@Link、@Prop、@Provied、@Consume、@ObjectLink、@StorageLink、@StorageProp、@LocalStorageLink和@LocalStorageProp装饰的变量装饰变量初始化子组件@Provide |
用于初始化子组件 | 允许,可用于初始化@State、@Link、@Prop、@Provide |
和父组件同步 | 否 |
和后代组件同步 | 和@Consume双向同步 |
是否支持组件外访问 | 私有,仅可以在所属组件内访问。 |
@Consume传递/访问 | 说明 |
从父组件初始化和更新 | 禁止。通过相同的变量名和alias(别名)从@Provide初始化 |
用于初始化子组件 | 允许,可用于初始化@State、@Link、@Prop、@Provide |
和祖先组件同步 | 和@Provide双向同步 |
是否支持组件外访问 | 私有,仅可以在所属组件内访问。 |
4.框架行为
(1)初始渲染:
- @Provide装饰的变量会以map的形式,传递给当前@Provide所属组件的所有子组件;
- 子组件中如果使用@Consume变量,则会在map中查找是否有该变量名/alias(别名)对应的@Provide的变量,如果查找不到,框架会抛出JS ERROR;
- 在初始化@Consume变量时,和@State/@Link的流程类似,@Consume变量会在map中查找到对应的@Provide变量进行保存,并把自己注册给@Provide。
(2)当@Provide装饰的数据变化时:
- 通过初始渲染的步骤可知,子组件@Consume已把自己注册给父组件。父组件@Provide变量变更后,会遍历更新所有依赖它的系统组件(elementid)和状态变量(@Consume)
- 通知@Consume更新后,子组件所有依赖@Consume的系统组件(elementld)都会被通知更新。以此实现@Provide对@Consume状态数据同步。
(3)当@Consume装饰的数据变化时:
通过初始渲染的步骤可知,子组件@Consume持有@Provide的实例。在@Cosume更新后调用@Provide的更新方法,将更新的数值同步回@Provide,以此实现@Consume向@Provide的同步更新。
5.限制条件
(1)@Provider/@Consumer的参数key必须为string,否则编译期会报错。
(2)@Consume装饰的变量不能本地初始化,也不能在构造参数中传入初始化,否则编译期会报错。@consume仅能通过key来匹配对应的@Provide变量进行初始化。
(3)@Provide的key重复定义时,框架会抛出运行时错误,提醒开发者重复定义key,如果开发者需要重复key,可以使用allowoverride。
(4)在初始化@Consume变量时,如果开发者没有定义对应key的@Provide变量,框架会抛出运行时错误,提示开发者初始化@Consume变量失败,原因是无法找到其对应key的@Provide变量。
(5)@Provide与@Consume不支持装饰Function类型的变量,框架会抛出运行时错误。
6.@Provide支持allowOverride参数
名称 | 类型 | 必填 | 说明 |
allowOverride | string | 否 | 是否允许@Provide重写。允许在同一组件树下通过allowOverride重写同名的@Provide。如果开发者未写allowOverride,定义同名的@Provide,运行时会报错。 |
7.常见问题
(1)@BuilderParam尾随闭包情况下@Provide未定义错误
在此场景下,CustomWidget执行this.builder()创建子组件CustomWidgetChild时,this指向的是HomePage。因此找不到CustomWidget的@Provide变量,所以下面示例会报找不到@Provide错误,和@BuilderParam连用的时候要谨慎this的指向。
(2)使用a.b(this.object)形式调用,不会触发UI刷新
在build方法内,当@Provide与@Consume装饰的变量是Object类型、且通过a.b(this.object)形式调用时,b方法内传入的是this.object的原生对象,修改其属性,无法触发UI刷新。如下例中,通过静态方法或者使用this调用组件内部方法,修改组件中的this.dog.age与this.dog.name时,UI不会刷新。可以通过先赋值、再调用新赋值的变量的方式,实现UI刷新。
(5)@Observed
@Observed装饰class,需要观察多层嵌套场景的class需要被@Observed装饰。单独使用@Observed没有任何作用,需要和@ObjectLink、@Prop联用。
(6)@ObjectLink
@ObjectLink装饰的变量接受@Observed装饰的class的实例,应用于观察多层嵌套场景、和父组件的数据源构建双向同步。
说明:仅@Observed/@ObjectLink可以观察嵌套场景,其他的状态变量仅能观察第一层。
2.管理应用级状态的装饰器
1.AppStorage是应用程序中的 一个特殊的单例LocalStorage对象,是应用级的数据库,和进程绑定,通过@StorageProp和@StorageLink装饰器可以和组件联动。
2.AppStorage是应用状态的‘中枢’,将需要与组件(UI)交互的数据存入AppStorage,比如持久化数据PersistentStorage和环境变量Environment。UI再通过AppStorage提供的装饰器或者API接口,访问这些数据。
3.框架还提供给了LocalStorage,AppStorage是LocalStorage特殊的单例。LoalStorage是应用程序声明的应用状态的内存‘数据库’,通常用于页面级的状态共享,通过@LocalStorageProp和@LocalStorageLink装饰器可以和UI联动。
3.@Watch装饰器
@Watch用于监听状态变量的变化。
$$运算符:给内置组件提供TS变量的引用,使得TS变量和内置组件的内部状态保持同步。