• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# \@Provide and \@Consume: Two-Way Synchronization with Descendant Components
2
3
4\@Provide and \@Consume are used for two-way data synchronization with descendant components in scenarios where state data needs to be transferred between multiple levels. They do not involve passing a variable from component to component multiple times.
5
6
7An \@Provide decorated state variable exists in the ancestor component and is said to be "provided" to descendent components. An \@Consume decorated state variable is used in a descendent component. It is linked to ("consumes") the provided state variable in its ancestor component.
8
9
10> **NOTE**
11>
12> Since API version 9, these two decorators are supported in ArkTS widgets.
13
14
15## Overview
16
17\@Provide/\@Consume decorated state variables have the following features:
18
19- An \@Provide decorated state variable becomes available to all descendent components of the providing component automatically. The variable is said to be "provided" to other components. This means that you do not need to pass a variable from component to component multiple times.
20
21- A descendent component gains access to the provided state variable by decorating a variable with \@Consume. This establishes a two-way data synchronization between the provided and the consumed variable. This synchronization works the same as a combination of \@State and \@Link does. The only difference is that the former allows transfer across multiple levels of the UI parent-child hierarchy.
22
23- \@Provide and \@Consume can be bound using the same variable name or variable alias. The variable types must be the same.
24
25
26```ts
27// Binding through the same variable name
28@Provide a: number = 0;
29@Consume a: number;
30
31// Binding through the same variable alias
32@Provide('a') b: number = 0;
33@Consume('a') c: number;
34```
35
36
37When \@Provide and \@Consume are bound through the same variable name or variable alias, the variables decorated by \@Provide and \@Consume are in a one-to-many relationship. A custom component, including its child components, cannot contain multiple \@Provide decorated variables under the same name or alias.
38
39
40## Decorator Description
41
42The rules of \@State also apply to \@Provide. The difference is that \@Provide also functions as a synchronization source for multi-layer descendants.
43
44| \@Provide Decorator| Description                                      |
45| -------------- | ---------------------------------------- |
46| Decorator parameters         | Alias: constant string, optional.<br>If the alias is specified, the variable is provided under the alias name only. If the alias is not specified, the variable is provided under the variable name.|
47| Synchronization type          | Two-way:<br>from the \@Provide decorated variable to all \@Consume decorated variables; and the other way around. The two-way synchronization behaviour is the same as that of the combination of \@State and \@Link.|
48| Allowed variable types     | Object, class, string, number, Boolean, enum, and array of these types. For details about the scenarios of nested types, see [Observed Changes](#observed-changes).<br>**any** is not supported. A combination of simple and complex types is not supported. The **undefined** and **null** values are not allowed.<br>The type must be specified. The type of the provided and the consumed variables must be the same.<br>**NOTE**<br>The Length, ResourceStr, and ResourceColor types are a combination of simple and complex types and therefore not supported.|
49| Initial value for the decorated variable     | Mandatory.                                   |
50
51| \@Consume Decorator| Description                                      |
52| -------------- | ---------------------------------------- |
53| Decorator parameters         | Alias: constant string, optional.<br>If the alias is specified, the alias name is used for matching with the \@Provide decorated variable. Otherwise, the variable name is used.|
54| Synchronization type          | from the \@Provide decorated variable to all \@Consume decorated variables; and the other way around. The two-way synchronization behaviour is the same as that of the combination of \@State and \@Link.|
55| Allowed variable types     | Object, class, string, number, Boolean, enum, and array of these types. For details about the scenarios of nested types, see [Observed Changes](#observed-changes).<br>**any** is not supported. The **undefined** and **null** values are not allowed.<br>The type must be specified. The type of the provided and the consumed variables must be the same.<br>**NOTE**<br>An \@Consume decorated variable must have a matching \@Provide decorated variable with the corresponding attribute and alias on its parent or ancestor node.|
56| Initial value for the decorated variable     | Forbidden.                              |
57
58
59## Variable Transfer/Access Rules
60
61
62| \@Provide Transfer/Access| Description                                      |
63| -------------- | ---------------------------------------- |
64| Initialization and update from the parent component    | Optional. An \@Provide decorated variable can be initialized from a regular variable or an \@State, \@Link, \@Prop, \@Provide, \@Consume, \@ObjectLink, \@StorageLink, \@StorageProp, \@LocalStorageLink, or \@LocalStorageProp decorated variable in its parent component.|
65| Subnode initialization      | Supported; can be used to initialize an \@State, \@Link, \@Prop, or \@Provide decorated variable in the child component.|
66| Synchronization with the parent component        | None.                                      |
67| Synchronization with descendant components       | Two-way with @Consume decorated variables in descendant components.                         |
68| Access     | Private, accessible only within the component.                         |
69
70
71  **Figure 1** \@Provide initialization rule
72
73
74![en-us_image_0000001552614217](figures/en-us_image_0000001552614217.png)
75
76
77| \@Consume Transfer/Access| Description                                      |
78| -------------- | ---------------------------------------- |
79| Initialization and update from the parent component    | Forbidden. Initialized from the \@Provide decorated variable with the same name or alias.     |
80| Subnode initialization      | Supported; can be used to initialize an \@State, \@Link, \@Prop, or \@Provide decorated variable in the child component.|
81| Synchronization with the ancestor component       | Two-way with the @Provide decorated variable in the ancestor component.                         |
82| Access     | Private, accessible only within the component.                          |
83
84
85  **Figure 2** \@Consume initialization rule
86
87
88![en-us_image_0000001502094666](figures/en-us_image_0000001502094666.png)
89
90
91## Observed Changes and Behavior
92
93
94### Observed Changes
95
96- When the decorated variable is of the Boolean, string, or number type, its value change can be observed.
97
98- When the decorated variable is of the class or Object type, its value change and value changes of all its attributes, that is, the attributes that **Object.keys(observedObject)** returns.
99
100- When the decorated variable is of the array type, the addition, deletion, and updates of array items can be observed.
101
102
103### Framework Behavior
104
1051. Initial render:
106   1. The \@Provide decorated variable is passed to all child components of the owning component in map mode.
107   2. If an \@Consume decorated variable is used in a child component, the system checks the map for a matching \@Provide decorated variable based on the variable name or alias. If no matching variable is found, the framework throws a JS error.
108   3. The process of initializing the \@Consume decorated variable is similar to that of initializing the \@State/\@Link decorated variable. The \@Consume decorated variable saves the matching \@Provide decorated variable found in the map and registers itself with the \@Provide decorated variable.
109
1102. When the \@Provide decorated variable is updated:
111   1. The system traverses and updates all system components (**elementid**) and state variable (\@Consume) that depend on the \@Provide decorated variable, with which the \@Consume decorated variable has registered itself on initial render.
112   2. After the \@Consume decorated variable is updated in all owning child components, all system components (**elementId**) that depend on the \@Consume decorated variable are updated. In this way, changes to the \@Provide decorated variable are synchronized to the \@Consume decorated variable.
113
1143. When the \@Consume decorated variable is updated:
115
116   As can be learned from the initial render procedure, the \@Consume decorated variable holds an instance of \@Provide. After the \@Consume decorated variable is updated, the update method of \@Provide is called to synchronize the changes to \@Provide.
117
118
119## Application Scenarios
120
121The following example shows the two-way synchronization between \@Provide and \@Consume decorated variables. When the buttons in the **CompA** and **CompD** components are clicked, the changes to **reviewVotes** are synchronized to the **CompA** and **CompD** components.
122
123
124
125```ts
126@Component
127struct CompD {
128  // The @Consume decorated variable is bound to the @Provide decorated variable in its ancestor component CompA under the same attribute name.
129  @Consume reviewVotes: number;
130
131  build() {
132    Column() {
133      Text(`reviewVotes(${this.reviewVotes})`)
134      Button(`reviewVotes(${this.reviewVotes}), give +1`)
135        .onClick(() => this.reviewVotes += 1)
136    }
137    .width('50%')
138  }
139}
140
141@Component
142struct CompC {
143  build() {
144    Row({ space: 5 }) {
145      CompD()
146      CompD()
147    }
148  }
149}
150
151@Component
152struct CompB {
153  build() {
154    CompC()
155  }
156}
157
158@Entry
159@Component
160struct CompA {
161  // @Provide decorated variable reviewVotes is provided by the entry component CompA.
162  @Provide reviewVotes: number = 0;
163
164  build() {
165    Column() {
166      Button(`reviewVotes(${this.reviewVotes}), give +1`)
167        .onClick(() => this.reviewVotes += 1)
168      CompB()
169    }
170  }
171}
172```
173