@Link decorador: sincronización bidireccional padre-hijo
La variable decorada con @Link en el componente secundario establece un enlace de datos bidireccional con la fuente de datos correspondiente en el componente principal.
descripción general
Una variable decorada con @Link comparte el mismo valor que su fuente de datos en su componente principal.
Descripción de las reglas de uso del decorador
Decorador de variables @Link |
ilustrar |
---|---|
parámetros del decorador |
ninguno |
Tipo de sincronización |
Sincronización bidireccional. @State, @StorageLink y @Link en el componente principal y @Link en el componente secundario pueden establecer una sincronización de datos bidireccional y viceversa. |
Tipos variables que permiten la decoración |
Objeto, clase, cadena, número, booleano, tipos de enumeración y matrices de estos tipos. El tipo debe especificarse y es el mismo que el tipo de la variable de estado de enlace bidireccional. No se admite ninguno, los tipos de unión de tipos simples y tipos complejos no se admiten, y no se permiten valores indefinidos y nulos. ilustrar Los tipos Longitud, ResourceStr y ResourceColor no se admiten, y Longitud, ResourceStr y ResourceColor son tipos de unión de tipos simples y tipos complejos. |
El valor inicial de la variable decorada. |
Ninguno, deshabilita la inicialización local. |
Explicación de las reglas de acceso/transferencia de variables
pase/acceso |
ilustrar |
---|---|
Inicializar y actualizar desde el componente principal |
requerido. Cree enlaces bidireccionales con los componentes principales @State, @StorageLink y @Link. Permita las variables de decoración @State, @Link, @Prop, @Provide, @Consume, @ObjectLink, @StorageLink, @StorageProp, @LocalStorageLink y @LocalStorageProp en el componente principal para inicializar el componente secundario @Link. A partir de la versión 9 de la API, el componente secundario @Link inicializa @State desde el componente principal con la sintaxis Comp({ aLink: this.aState }). Comp({aLink: $aState}) también es compatible. |
Se utiliza para inicializar componentes secundarios |
Permitido, puede usarse para inicializar variables regulares, @State, @Link, @Prop, @Provide. |
Ya sea para admitir el acceso fuera del componente |
Privado y solo se puede acceder desde el componente propietario. |
Figura 1 Ilustración de las reglas de inicialización
Observar los cambios y el comportamiento.
observar cambios
- Cuando el tipo de datos de la decoración es booleano, cadena o número, el cambio del valor se puede observar sincrónicamente.
- Cuando el tipo de datos decorado es clase u objeto, puede observar los cambios de asignación y asignación de atributos, es decir, todos los atributos devueltos por Object.keys (observedObject).
- Cuando el objeto decorado es una matriz, puede observar los cambios al agregar, eliminar y actualizar las celdas de la matriz en la matriz.
comportamiento del marco
Las variables decoradas con @Link comparten un ciclo de vida con el componente personalizado que describen.
Para comprender el mecanismo de inicialización y actualización de la variable @Link, es necesario comprender la relación entre el componente principal y el componente secundario que posee la variable @Link, el proceso de representación inicial y la actualización bidireccional (tome el componente principal como @ Estado como ejemplo).
- Representación inicial: se creará una nueva instancia del componente secundario después de ejecutar la función build() del componente principal. El proceso de inicialización es el siguiente:
- La variable @State en el componente principal debe especificarse para inicializar la variable @Link del componente secundario. El valor de la variable @Link del componente secundario se mantiene sincronizado con la variable de origen de datos de su componente principal (sincronización de datos bidireccional).
- La clase contenedora de la variable de estado @State del componente principal se pasa al componente secundario a través del constructor.Después de que la clase contenedora @Link del componente secundario obtiene la variable de estado @State del componente principal, registra la clase contenedora @Link actual este puntero a la clase contenedora @Link del componente padre Variables de estado.
- La actualización de la fuente de datos de @Link: es decir, la actualización de la variable de estado en el componente principal provoca la actualización de @Link del componente secundario relacionado. Pasos de procesamiento:
- A través de los pasos de la representación inicial, podemos ver que la clase contenedora @Link del componente secundario registra el puntero this actual en el componente principal. Después de cambiar la variable @State del componente principal, recorrerá y actualizará todos los componentes del sistema (elementid) y las variables de estado (como las clases contenedoras @Link) que dependen de él.
- Después de notificar la actualización de la clase contenedora @Link, se notificará la actualización a todos los componentes del sistema (elementId) que dependen de la variable de estado @Link en el subcomponente. De esta forma, se realiza la sincronización de datos de estado del componente padre con el componente hijo.
- Actualización de @Link: cuando se actualiza @Link en el componente secundario, los pasos de procesamiento son los siguientes (tome el componente principal como @State como ejemplo):
- Después de actualizar @Link, llame al método set de la clase contenedora @State del componente principal para sincronizar el valor actualizado con el componente principal.
- El componente secundario @Link y el componente principal @State atraviesan respectivamente los componentes dependientes del sistema y actualizan la interfaz de usuario correspondiente. De esta forma, el componente secundario @Link se vuelve a sincronizar con el componente principal @State.
Escenas a utilizar
@Link para tipos simples y tipos similares a objetos
En el siguiente ejemplo, haga clic en "Vista principal: Establecer botón amarillo" y "Vista principal: Establecer botón verde" en el componente principal ShufflingContainer para sincronizar los cambios del componente principal con los componentes secundarios y los cambios de las variables de decoración @Link en el componente secundario. Los componentes GreenButton y YellowButton también se sincronizarán con su componente principal.
class GreenButtonState {
width: number = 0;
constructor(width: number) {
this.width = width;
}
}
@Component
struct GreenButton {
@Link greenButtonState: GreenButtonState;
build() {
Button('Green Button')
.width(this.greenButtonState.width)
.height(150.0)
.backgroundColor('#00ff00')
.onClick(() => {
if (this.greenButtonState.width < 700) {
// 更新class的属性,变化可以被观察到同步回父组件
this.greenButtonState.width += 125;
} else {
// 更新class,变化可以被观察到同步回父组件
this.greenButtonState = new GreenButtonState(100);
}
})
}
}
@Component
struct YellowButton {
@Link yellowButtonState: number;
build() {
Button('Yellow Button')
.width(this.yellowButtonState)
.height(150.0)
.backgroundColor('#ffff00')
.onClick(() => {
// 子组件的简单类型可以同步回父组件
this.yellowButtonState += 50.0;
})
}
}
@Entry
@Component
struct ShufflingContainer {
@State greenButtonState: GreenButtonState = new GreenButtonState(300);
@State yellowButtonProp: number = 100;
build() {
Column() {
// 简单类型从父组件@State向子组件@Link数据同步
Button('Parent View: Set yellowButton')
.onClick(() => {
this.yellowButtonProp = (this.yellowButtonProp < 700) ? this.yellowButtonProp + 100 : 100;
})
// class类型从父组件@State向子组件@Link数据同步
Button('Parent View: Set GreenButton')
.onClick(() => {
this.greenButtonState.width = (this.greenButtonState.width < 700) ? this.greenButtonState.width + 100 : 100;
})
// class类型初始化@Link
GreenButton({ greenButtonState: $greenButtonState })
// 简单类型初始化@Link
YellowButton({ yellowButtonState: $yellowButtonProp })
}
}
}
@Enlace de tipo de matriz
@Component
struct Child {
@Link items: number[];
build() {
Column() {
Button(`Button1: push`).onClick(() => {
this.items.push(this.items.length + 1);
})
Button(`Button2: replace whole item`).onClick(() => {
this.items = [100, 200, 300];
})
}
}
}
@Entry
@Component
struct Parent {
@State arr: number[] = [1, 2, 3];
build() {
Column() {
Child({ items: $arr })
ForEach(this.arr,
item => {
Text(`${item}`)
},
item => item.toString()
)
}
}
}
Como se mencionó anteriormente, el marco ArkUI puede observar la adición, eliminación y reemplazo de elementos de matriz. En este ejemplo, los tipos de @State y @Link son el mismo número[], no está permitido definir @Link como un tipo de número (@Link item: number), y crearlo con cada elemento de datos en el @State matriz en el subensamblaje del componente padre.
@Provide decorador y @Consume decorador: sincronización bidireccional con componentes descendientes
@Provide y @Consume se aplican a la sincronización bidireccional de datos con componentes descendientes y se aplican a escenarios en los que los datos de estado pasan entre varios niveles. A diferencia del paso mencionado anteriormente entre los componentes padre e hijo a través del mecanismo de parámetros con nombre, @Provide y @Consume se deshacen de los grilletes del mecanismo de paso de parámetros y realizan el paso entre niveles.
La variable decorada con @Provide está en el nodo ancestro, que puede entenderse como una variable de estado que se "proporciona" a los descendientes. La variable decorada con @Consume es para "consumir (vincular)" la variable proporcionada por el nodo ancestro en el componente descendiente.
descripción general
Las variables de estado decoradas con @Provide/@Consume tienen las siguientes características:
- La variable de estado decorada por @Provide está automáticamente disponible para todos sus componentes descendientes, es decir, la variable se "proporciona" a sus componentes descendientes. Se puede ver que la conveniencia de @Provide es que los desarrolladores no necesitan pasar variables entre componentes varias veces.
- Los descendientes utilizan @Consume para obtener las variables proporcionadas por @Provide y establecen una sincronización de datos bidireccional entre @Provide y @Consume. A diferencia de @State/@Link, el primero puede pasarse entre componentes padre-hijo de varios niveles.
- @Provide y @Consume pueden vincularse con el mismo nombre de variable o el mismo alias de variable, y los tipos de variable deben ser los mismos.
// 通过相同的变量名绑定
@Provide a: number = 0;
@Consume a: number;
// 通过相同的变量别名绑定
@Provide('a') b: number = 0;
@Consume('a') c: number;
Descripción del decorador
Las reglas de @State también se aplican a @Provide, la diferencia es que @Provide también actúa como una fuente de sincronización para varios descendientes.
@Proporcionar decorador variable |
ilustrar |
---|---|
parámetros del decorador |
alias: const string, opcional. Si se especifica un alias, la variable está vinculada por el alias; si no se especifica ningún alias, la variable está vinculada por el nombre de la variable. |
Tipo de sincronización |
Sincronización bidireccional. Sincronización de datos de las variables @Provide a todas las variables @Consume y viceversa. La operación de sincronización bidireccional es la misma que la combinación de @State y @Link. |
Tipos variables que permiten la decoración |
Objeto, clase, cadena, número, booleano, tipos de enumeración y matrices de estos tipos. No se admite ninguno, los tipos de unión de tipos simples y tipos complejos no se admiten, y no se permiten valores indefinidos y nulos. Se debe especificar el tipo. La variable @Consume debe ser del mismo tipo que la variable @Provide. ilustrar Los tipos Longitud, ResourceStr y ResourceColor no se admiten, y Longitud, ResourceStr y ResourceColor son tipos de unión de tipos simples y tipos complejos. |
El valor inicial de la variable decorada. |
debe especificarse. |
@Consume decorador de variables |
ilustrar |
---|---|
parámetros del decorador |
alias: const string, opcional. Si se proporciona un alias, la variable @Provide debe tener el mismo alias para que coincida correctamente; de lo contrario, el nombre de la variable debe ser el mismo para que coincida correctamente. |
Tipo de sincronización |
Bidireccional: desde variables @Provide (ver @Provide para más detalles) a todas las variables @Consume, y viceversa. La sincronización bidireccional funciona igual que la combinación de @State y @Link. |
Tipos variables que permiten la decoración |
Objeto, clase, cadena, número, booleano, tipos de enumeración y matrices de estos tipos. any no es compatible, y no se permiten undefined y null. Se debe especificar el tipo. La variable @Consume debe ser del mismo tipo que la variable @Provide. ilustrar
|
El valor inicial de la variable decorada. |
Ninguno, deshabilita la inicialización local. |
Explicación de las reglas de acceso/transferencia de variables
@Proporcionar pase/acceso |
ilustrar |
---|---|
Inicializar y actualizar desde el componente principal |
可选,允许父组件中常规变量、@State、@Link、@Prop、@Provide、@Consume、@ObjectLink、@StorageLink、@StorageProp、@LocalStorageLink和@LocalStorageProp装饰的变量装饰变量初始化子组件@Provide。 |
用于初始化子组件 |
允许,可用于初始化@State、@Link、@Prop、@Provide。 |
和父组件同步 |
否。 |
和后代组件同步 |
和@Consume双向同步。 |
是否支持组件外访问 |
私有,仅可以在所属组件内访问。 |
图1 @Provide初始化规则图示
@Consume传递/访问 |
说明 |
---|---|
从父组件初始化和更新 |
禁止。通过相同的变量名和alias(别名)从@Provide初始化。 |
用于初始化子组件 |
允许,可用于初始化@State、@Link、@Prop、@Provide。 |
和祖先组件同步 |
和@Provide双向同步。 |
是否支持组件外访问 |
私有,仅可以在所属组件内访问 |
图2 @Consume初始化规则图示
观察变化和行为表现
观察变化
- 当装饰的数据类型为boolean、string、number类型时,可以观察到数值的变化。
- 当装饰的数据类型为class或者Object的时候,可以观察到赋值和属性赋值的变化(属性为Object.keys(observedObject)返回的所有属性)。
- 当装饰的对象是array的时候,可以观察到数组的添加、删除、更新数组单元。
框架行为
- 初始渲染:
- @Provide装饰的变量会以map的形式,传递给当前@Provide所属组件的所有子组件;
- 子组件中如果使用@Consume变量,则会在map中查找是否有该变量名/alias(别名)对应的@Provide的变量,如果查找不到,框架会抛出JS ERROR;
- 在初始化@Consume变量时,和@State/@Link的流程类似,@Consume变量会保存在map中查找到的@Provide变量,并把自己注册给@Provide。
- 当@Provide装饰的数据变化时:
- 通过初始渲染的步骤可知,子组件@Consume已把自己注册给父组件。父组件@Provide变量变更后,会遍历更新所有依赖它的系统组件(elementid)和状态变量(@Consume);
- 通知@Consume更新后,子组件所有依赖@Consume的系统组件(elementId)都会被通知更新。以此实现@Provide对@Consume状态数据同步。
- 当@Consume装饰的数据变化时:
- 通过初始渲染的步骤可知,子组件@Consume持有@Provide的实例。在@Consume更新后调用@Provide的更新方法,将更新的数值同步回@Provide,以此实现@Consume向@Provide的同步更新。
使用场景
在下面的示例是与后代组件双向同步状态@Provide和@Consume场景。当分别点击CompA和CompD组件内Button时,reviewVotes 的更改会双向同步在CompA和CompD中。
@Component
struct CompD {
// @Consume装饰的变量通过相同的属性名绑定其祖先组件CompA内的@Provide装饰的变量
@Consume reviewVotes: number;
build() {
Column() {
Text(`reviewVotes(${this.reviewVotes})`)
Button(`reviewVotes(${this.reviewVotes}), give +1`)
.onClick(() => this.reviewVotes += 1)
}
.width('50%')
}
}
@Component
struct CompC {
build() {
Row({ space: 5 }) {
CompD()
CompD()
}
}
}
@Component
struct CompB {
build() {
CompC()
}
}
@Entry
@Component
struct CompA {
// @Provide装饰的变量reviewVotes由入口组件CompA提供其后代组件
@Provide reviewVotes: number = 0;
build() {
Column() {
Button(`reviewVotes(${this.reviewVotes}), give +1`)
.onClick(() => this.reviewVotes += 1)
CompB()
}
}
}