• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# \@State Decorator: State Owned by Component
2
3
4An \@State decorated variable, also called a state variable, is a variable that holds the state property and is used to render the owning custom component. When it changes, the UI is re-rendered accordingly.
5
6
7Among the decorators related to state variables, \@State is the most basic decorator, as it is the one that empowers variables to have the state property. It is also the data source of most state variables.
8
9
10> **NOTE**
11>
12> Since API version 9, this decorator is supported in ArkTS widgets.
13
14
15## Overview
16
17An @State decorated variable, like all other decorated variables in the declarative paradigm, are private and only accessible from within the component. Its type and its local initialization must be specified. Initialization from the parent component using the named parameter mechanism is accepted.
18
19\@State decorated variables have the following features:
20
21- A one-way and two-way data synchronization relationship can be set up from an \@State decorated variable to an \@Prop, \@Link, or \@ObjectLink decorated variable in a child component.
22
23- The lifecycle of the \@State decorated variable is the same as that of its owning custom component.
24
25
26## Rules of Use
27
28| \@State Decorator | Description                                                        |
29| ------------------ | ------------------------------------------------------------ |
30| Decorator parameters        | None.                                                          |
31| Synchronization type          | Does not synchronize with any type of variable in the parent component.                            |
32| Allowed variable types| Object, class, string, number, Boolean, enum, and array of these types.<br>Date type.<br>For details about the scenarios of supported types, see [Observed Changes](#observed-changes).<br>The type must be specified.<br>**any** is not supported. A combination of simple and complex types is not supported. The **undefined** and **null** values are not allowed.<br>**NOTE**<br>The Length, ResourceStr, and ResourceColor types are a combination of simple and complex types and therefore not supported.|
33| Initial value for the decorated variable| Local initialization is required.                                              |
34
35
36## Variable Transfer/Access Rules
37
38| Transfer/Access         | Description                                                        |
39| ------------------ | ------------------------------------------------------------ |
40| Initialization from the parent component    | Optional. Initialization from the parent component or local initialization can be used. The initial value specified in the parent component will overwrite the one defined locally.<br>An @State decorated variable can be initialized from a regular variable (whose change does not trigger UI refresh) or an @State, @Link, @Prop, @Provide, @Consume, @ObjectLink, @StorageLink, @StorageProp, @LocalStorageLink, or @LocalStorageProp decorated variable in its parent component.|
41| Subnode initialization  | Supported. An \@State decorated variable can be used to initialize a regular variable or \@State, \@Link, \@Prop, or \@Provide decorated variable in the child component.|
42| Access| Private, accessible only within the component.                                  |
43
44  **Figure 1** Initialization rule
45
46![en-us_image_0000001502091796](figures/en-us_image_0000001502091796.png)
47
48
49## Observed Changes and Behavior
50
51Not all changes to state variables cause UI updates. Only changes that can be observed by the framework do. This section describes what changes can be observed and how the framework triggers UI updates after the changes are observed, that is, how the framework behaves.
52
53
54### Observed Changes
55
56- When the decorated variable is of the Boolean, string, or number type, its value change can be observed.
57
58  ```ts
59  // for simple type
60  @State count: number = 0;
61  // value changing can be observed
62  this.count = 1;
63  ```
64
65- 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. Below is an example.
66    Declare the **ClassA** and **Model** classes.
67
68    ```ts
69      class ClassA {
70        public value: string;
71
72        constructor(value: string) {
73          this.value = value;
74        }
75      }
76
77      class Model {
78        public value: string;
79        public name: ClassA;
80        constructor(value: string, a: ClassA) {
81          this.value = value;
82          this.name = a;
83        }
84      }
85    ```
86
87    Use \@State to decorate a variable of the Model class object type.
88
89    ```ts
90    // Class type
91     @State title: Model = new Model('Hello', new ClassA('World'));
92    ```
93
94    Assign a value to the \@State decorated variable.
95
96    ```ts
97    // Assign a value to the class object.
98    this.title = new Model('Hi', new ClassA('ArkUI'));
99    ```
100
101    Assign a value to an attribute of the \@State decorated variable.
102
103    ```ts
104    // Assign a value to an attribute of the class object.
105    this.title.value = 'Hi'
106    ```
107
108    The value assignment of the nested attribute cannot be observed.
109
110    ```ts
111    // The value assignment of the nested attribute cannot be observed.
112    this.title.name.value = 'ArkUI'
113    ```
114- When the decorated variable is of the array type, the addition, deletion, and updates of array items can be observed. Below is an example.
115  Declare the **ClassA** and **Model** classes.
116
117  ```ts
118  class Model {
119    public value: number;
120    constructor(value: number) {
121      this.value = value;
122    }
123  }
124  ```
125
126  Use \@State to decorate a variable of the Model class array type.
127
128  ```ts
129  @State title: Model[] = [new Model(11), new Model(1)]
130  ```
131
132  The value assignment of the array itself can be observed.
133
134  ```ts
135  this.title = [new Model(2)]
136  ```
137
138  The value assignment of array items can be observed.
139
140  ```ts
141  this.title[0] = new Model(2)
142  ```
143
144  The deletion of array items can be observed.
145
146  ```ts
147  this.title.pop()
148  ```
149
150  The addition of array items can be observed.
151
152  ```ts
153  this.title.push(new Model(12))
154  ```
155
156- When the decorated variable is of the Date type, the overall value assignment of the Date object can be observed, and the following APIs can be called to update Date attributes: **setFullYear**, **setMonth**, **setDate**, **setHours**, **setMinutes**, **setSeconds**, **setMilliseconds**, **setTime**, **setUTCFullYear**, **setUTCMonth**, **setUTCDate**, **setUTCHours**, **setUTCMinutes**, **setUTCSeconds**, and **setUTCMilliseconds**.
157
158  ```ts
159  @Entry
160  @Component
161  struct DatePickerExample {
162    @State selectedDate: Date = new Date('2021-08-08')
163
164    build() {
165      Column() {
166        Button('set selectedDate to 2023-07-08')
167          .margin(10)
168          .onClick(() => {
169            this.selectedDate = new Date('2023-07-08')
170          })
171        Button('increase the year by 1')
172          .margin(10)
173          .onClick(() => {
174            this.selectedDate.setFullYear(this.selectedDate.getFullYear() + 1)
175          })
176        Button('increase the month by 1')
177          .margin(10)
178          .onClick(() => {
179            this.selectedDate.setMonth(this.selectedDate.getMonth() + 1)
180          })
181        Button('increase the day by 1')
182          .margin(10)
183          .onClick(() => {
184            this.selectedDate.setDate(this.selectedDate.getDate() + 1)
185          })
186        DatePicker({
187          start: new Date('1970-1-1'),
188          end: new Date('2100-1-1'),
189          selected: this.selectedDate
190        })
191      }.width('100%')
192    }
193  }
194  ```
195
196### Framework Behavior
197
198- When a state variable is changed, the framework searches for components that depend on this state variable.
199
200- The framework executes an update method of the dependent components, which triggers re-rendering of the components.
201
202- Components or UI descriptions irrelevant to the state variable are not re-rendered, thereby implementing on-demand page updates.
203
204
205## Application Scenarios
206
207
208### Decorating Variables of Simple Types
209
210In this example, \@State is used to decorate the **count** variable of the simple type, turning it into a state variable. The change of **count** causes the update of the **\<Button>** component.
211
212- When **count** changes, the framework searches for components bound to it, which include only the **\<Button>** component in this example.
213
214- The framework executes the update method of the **\<Button>** component to implement on-demand update.
215
216
217```ts
218@Entry
219@Component
220struct MyComponent {
221  @State count: number = 0;
222
223  build() {
224    Button(`click times: ${this.count}`)
225      .onClick(() => {
226        this.count += 1;
227      })
228  }
229}
230```
231
232
233### Decorating Variables of the Class Object Type
234
235- In this example, \@State is used to decorate the variables **count** and **title** in the custom component **MyComponent**. The type of **title** is **Model**, a custom class. If the value of **count** or **title** changes, the framework searches for all **MyComponent** instances that depend on these variables and triggers re-rendering of them.
236
237- The **EntryComponent** has multiple **MyComponent** instances. The internal state change of the first **MyComponent** instance does not affect the second **MyComponent** instance.
238
239
240
241```ts
242class Model {
243  public value: string;
244
245  constructor(value: string) {
246    this.value = value;
247  }
248}
249
250@Entry
251@Component
252struct EntryComponent {
253  build() {
254    Column() {
255      // The parameters specified here will overwrite the default values defined locally during initial render. Not all parameters need to be initialized from the parent component.
256      MyComponent({ count: 1, increaseBy: 2 })
257      MyComponent({ title: new Model('Hello, World 2'), count: 7 })
258    }
259  }
260}
261
262@Component
263struct MyComponent {
264  @State title: Model = new Model('Hello World');
265  @State count: number = 0;
266  private increaseBy: number = 1;
267
268  build() {
269    Column() {
270      Text(`${this.title.value}`)
271      Button(`Click to change title`).onClick(() => {
272        // The update of the @State decorated variable triggers the update of the <Text> component.
273        this.title.value = this.title.value === 'Hello ArkUI' ? 'Hello World' : 'Hello ArkUI';
274      })
275
276      Button(`Click to increase count=${this.count}`).onClick(() => {
277        // The update of the @State decorated variable triggers the update of the <Button> component.
278        this.count += this.increaseBy;
279      })
280    }
281  }
282}
283```
284
285
286From this example, we learn the initialization process of an \@State decorated variable on initial render.
287
288
2891. Apply the locally defined default value.
290
291   ```ts
292   @State title: Model = new Model('Hello World');
293   @State count: number = 0;
294   ```
295
2962. Apply the named parameter value, if one is provided.
297
298   ```ts
299   class C1 {
300      public count:number;
301      public increaseBy:number;
302      constructor(count: number, increaseBy:number) {
303      this.count = count;
304      this.increaseBy = increaseBy;
305     }
306   }
307   let obj = new C1(1, 2)
308   MyComponent(obj)
309   ```
310