• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# \@Prop装饰器:父子单向同步
2
3
4\@Prop装饰的变量可以和父组件建立单向的同步关系。\@Prop装饰的变量是可变的,但是变化不会同步回其父组件。
5
6
7> **说明:**
8>
9> 从API version 9开始,该装饰器支持在ArkTS卡片中使用。
10
11
12## 概述
13
14\@Prop装饰的变量和父组件建立单向的同步关系:
15
16- \@Prop变量允许在本地修改,但修改后的变化不会同步回父组件。
17
18- 当数据源更改时,\@Prop装饰的变量都会更新,并且会覆盖本地所有更改。因此,数值的同步是父组件到子组件(所属组件),子组件数值的变化不会同步到父组件。
19
20
21## 装饰器使用规则说明
22
23| \@Prop变量装饰器 | 说明                                       |
24| ----------- | ---------------------------------------- |
25| 装饰器参数       | 无                                        |
26| 同步类型        | 单向同步:对父组件状态变量值的修改,将同步给子组件\@Prop装饰的变量,子组件\@Prop变量的修改不会同步到父组件的状态变量上。嵌套类型的场景请参考[观察变化](#观察变化)。 |
27| 允许装饰的变量类型   | Object、class、string、number、boolean、enum类型,以及这些类型的数组。<br/>不支持any,支持undefined和null。<br/>支持Date类型。<br/>支持类型的场景请参考[观察变化](#观察变化)。<br/>支持上述支持类型的联合类型,比如string \| number, string \| undefined 或者 ClassA \| null,示例见[@Prop支持联合类型实例](#@Prop支持联合类型实例)。 <br/>**注意**<br/>当使用undefined和null的时候,建议显式指定类型,遵循TypeScipt类型校验,比如:`@Prop a : string \| undefined = undefiend`是推荐的,不推荐`@Prop a: string = undefined`。
28<br/>支持AkrUI框架定义的联合类型Length、ResourceStr、ResourceColor类型。 <br/>必须指定类型。<br/>**说明** :<br/>\@Prop和[数据源](arkts-state-management-overview.md#基本概念)类型需要相同,有以下三种情况:<br/>-&nbsp;\@Prop装饰的变量和\@State以及其他装饰器同步时双方的类型必须相同,示例请参考[父组件@State到子组件@Prop简单数据类型同步](#父组件state到子组件prop简单数据类型同步)。<br/>-&nbsp;\@Prop装饰的变量和\@State以及其他装饰器装饰的数组的项同步时 ,\@Prop的类型需要和\@State装饰的数组的数组项相同,比如\@Prop&nbsp;:&nbsp;T和\@State&nbsp;:&nbsp;Array&lt;T&gt;,示例请参考[父组件@State数组中的项到子组件@Prop简单数据类型同步](#父组件state数组项到子组件prop简单数据类型同步);<br/>-&nbsp;当父组件状态变量为Object或者class时,\@Prop装饰的变量和父组件状态变量的属性类型相同,示例请参考[从父组件中的@State类对象属性到@Prop简单类型的同步](#从父组件中的state类对象属性到prop简单类型的同步)。 |
29| 嵌套传递层数        | 在组件复用场景,建议@Prop深度嵌套数据不要超过5层,嵌套太多会导致深拷贝占用的空间过大以及GarbageCollection(垃圾回收),引起性能问题,此时更建议使用[\@ObjectLink](arkts-observed-and-objectlink.md)。如果子组件的数据不想同步回父组件,建议采用@Reusable中的aboutToReuse,实现父组件向子组件传递数据,具体用例请参考[组件复用场景](arkts-state-management-best-practices.md)。 |
30| 被装饰变量的初始值   | 允许本地初始化。                                 |
31
32
33## 变量的传递/访问规则说明
34
35| 传递/访问     | 说明                                       |
36| --------- | ---------------------------------------- |
37| 从父组件初始化   | 如果本地有初始化,则是可选的。没有的话,则必选,支持父组件中的常规变量(常规变量对@Prop赋值,只是数值的初始化,常规变量的变化不会触发UI刷新。只有状态变量才能触发UI刷新)、\@State、\@Link、\@Prop、\@Provide、\@Consume、\@ObjectLink、\@StorageLink、\@StorageProp、\@LocalStorageLink和\@LocalStorageProp去初始化子组件中的\@Prop变量。 |
38| 用于初始化子组件  | \@Prop支持去初始化子组件中的常规变量、\@State、\@Link、\@Prop、\@Provide。 |
39| 是否支持组件外访问 | \@Prop装饰的变量是私有的,只能在组件内访问。                |
40
41
42  **图1** 初始化规则图示  
43
44
45![zh-cn_image_0000001552972029](figures/zh-cn_image_0000001552972029.png)
46
47
48## 观察变化和行为表现
49
50
51### 观察变化
52
53\@Prop装饰的数据可以观察到以下变化。
54
55- 当装饰的类型是允许的类型,即Object、class、string、number、boolean、enum类型都可以观察到赋值的变化。
56
57  ```ts
58  // 简单类型
59  @Prop count: number;
60  // 赋值的变化可以被观察到
61  this.count = 1;
62  // 复杂类型
63  @Prop count: Model;
64  // 可以观察到赋值的变化
65  this.title = new Model('Hi');
66  ```
67
68当装饰的类型是Object或者class复杂类型时,可以观察到第一层的属性的变化,属性即Object.keys(observedObject)返回的所有属性;
69
70```
71class ClassA {
72  public value: string;
73  constructor(value: string) {
74    this.value = value;
75  }
76}
77class Model {
78  public value: string;
79  public a: ClassA;
80  constructor(value: string, a: ClassA) {
81    this.value = value;
82    this.a = a;
83  }
84}
85
86@Prop title: Model;
87// 可以观察到第一层的变化
88this.title.value = 'Hi'
89// 观察不到第二层的变化
90this.title.a.value = 'ArkUi'
91```
92
93对于嵌套场景,如果class是被\@Observed装饰的,可以观察到class属性的变化,示例请参考[@Prop嵌套场景](#@Prop嵌套场景)。
94
95当装饰的类型是数组的时候,可以观察到数组本身的赋值、添加、删除和更新。
96
97```
98// @State装饰的对象为数组时
99@Prop title: string[]
100// 数组自身的赋值可以观察到
101this.title = ['1']
102// 数组项的赋值可以观察到
103this.title[0] = '2'
104// 删除数组项可以观察到
105this.title.pop()
106// 新增数组项可以观察到
107this.title.push('3')
108```
109
110对于\@State和\@Prop的同步场景:
111
112- 使用父组件中\@State变量的值初始化子组件中的\@Prop变量。当\@State变量变化时,该变量值也会同步更新至\@Prop变量。
113- \@Prop装饰的变量的修改不会影响其数据源\@State装饰变量的值。
114- 除了\@State,数据源也可以用\@Link或\@Prop装饰,对\@Prop的同步机制是相同的。
115- 数据源和\@Prop变量的类型需要相同,\@Prop允许简单类型和class类型。
116
117- 当装饰的对象是Date时,可以观察到Date整体的赋值,同时可通过调用Date的接口`setFullYear`, `setMonth`, `setDate`, `setHours`, `setMinutes`, `setSeconds`, `setMilliseconds`, `setTime`, `setUTCFullYear`, `setUTCMonth`, `setUTCDate`, `setUTCHours`, `setUTCMinutes`, `setUTCSeconds`, `setUTCMilliseconds` 更新Date的属性。
118
119```ts
120@Component
121struct DateComponent {
122  @Prop selectedDate: Date = new Date('');
123
124  build() {
125    Column() {
126      Button('child update the new date')
127        .margin(10)
128        .onClick(() => {
129          this.selectedDate = new Date('2023-09-09')
130        })
131      Button(`child increase the year by 1`).onClick(() => {
132        this.selectedDate.setFullYear(this.selectedDate.getFullYear() + 1)
133      })
134      DatePicker({
135        start: new Date('1970-1-1'),
136        end: new Date('2100-1-1'),
137        selected: this.selectedDate
138      })
139    }
140  }
141}
142
143@Entry
144@Component
145struct ParentComponent {
146  @State parentSelectedDate: Date = new Date('2021-08-08');
147
148  build() {
149    Column() {
150      Button('parent update the new date')
151        .margin(10)
152        .onClick(() => {
153          this.parentSelectedDate = new Date('2023-07-07')
154        })
155      Button('parent increase the day by 1')
156        .margin(10)
157        .onClick(() => {
158          this.parentSelectedDate.setDate(this.parentSelectedDate.getDate() + 1)
159        })
160      DatePicker({
161        start: new Date('1970-1-1'),
162        end: new Date('2100-1-1'),
163        selected: this.parentSelectedDate
164      })
165
166      DateComponent({selectedDate:this.parentSelectedDate})
167    }
168
169  }
170}
171```
172
173### 框架行为
174
175要理解\@Prop变量值初始化和更新机制,有必要了解父组件和拥有\@Prop变量的子组件初始渲染和更新流程。
176
1771. 初始渲染:
178   1. 执行父组件的build()函数将创建子组件的新实例,将数据源传递给子组件;
179   2. 初始化子组件\@Prop装饰的变量。
180
1812. 更新:
182   1. 子组件\@Prop更新时,更新仅停留在当前子组件,不会同步回父组件;
183   2. 当父组件的数据源更新时,子组件的\@Prop装饰的变量将被来自父组件的数据源重置,所有\@Prop装饰的本地的修改将被父组件的更新覆盖。
184
185
186## 使用场景
187
188
189### 父组件\@State到子组件\@Prop简单数据类型同步
190
191
192以下示例是\@State到子组件\@Prop简单数据同步,父组件ParentComponent的状态变量countDownStartValue初始化子组件CountDownComponent中\@Prop装饰的count,点击“Try again”,count的修改仅保留在CountDownComponent 不会同步给父组件ParentComponent。
193
194
195ParentComponent的状态变量countDownStartValue的变化将重置CountDownComponent的count。
196
197
198
199```ts
200@Component
201struct CountDownComponent {
202  @Prop count: number = 0;
203  costOfOneAttempt: number = 1;
204
205  build() {
206    Column() {
207      if (this.count > 0) {
208        Text(`You have ${this.count} Nuggets left`)
209      } else {
210        Text('Game over!')
211      }
212      // @Prop装饰的变量不会同步给父组件
213      Button(`Try again`).onClick(() => {
214        this.count -= this.costOfOneAttempt;
215      })
216    }
217  }
218}
219
220@Entry
221@Component
222struct ParentComponent {
223  @State countDownStartValue: number = 10;
224
225  build() {
226    Column() {
227      Text(`Grant ${this.countDownStartValue} nuggets to play.`)
228      // 父组件的数据源的修改会同步给子组件
229      Button(`+1 - Nuggets in New Game`).onClick(() => {
230        this.countDownStartValue += 1;
231      })
232      // 父组件的修改会同步给子组件
233      Button(`-1  - Nuggets in New Game`).onClick(() => {
234        this.countDownStartValue -= 1;
235      })
236
237      CountDownComponent({ count: this.countDownStartValue, costOfOneAttempt: 2 })
238    }
239  }
240}
241```
242
243
244在上面的示例中:
245
246
2471. CountDownComponent子组件首次创建时其\@Prop装饰的count变量将从父组件\@State装饰的countDownStartValue变量初始化;
248
2492. 按“+1”或“-1”按钮时,父组件的\@State装饰的countDownStartValue值会变化,这将触发父组件重新渲染,在父组件重新渲染过程中会刷新使用countDownStartValue状态变量的UI组件并单向同步更新CountDownComponent子组件中的count值;
250
2513. 更新count状态变量值也会触发CountDownComponent的重新渲染,在重新渲染过程中,评估使用count状态变量的if语句条件(this.count &gt; 0),并执行true分支中的使用count状态变量的UI组件相关描述来更新Text组件的UI显示;
252
2534. 当按下子组件CountDownComponent的“Try again”按钮时,其\@Prop变量count将被更改,但是count值的更改不会影响父组件的countDownStartValue值;
254
2555. 父组件的countDownStartValue值会变化时,父组件的修改将覆盖掉子组件CountDownComponent中count本地的修改。
256
257
258### 父组件\@State数组项到子组件\@Prop简单数据类型同步
259
260
261父组件中\@State如果装饰的数组,其数组项也可以初始化\@Prop。以下示例中父组件Index中\@State装饰的数组arr,将其数组项初始化子组件Child中\@Prop装饰的value。
262
263
264
265```ts
266@Component
267struct Child {
268  @Prop value: number = 0;
269
270  build() {
271    Text(`${this.value}`)
272      .fontSize(50)
273      .onClick(()=>{this.value++})
274  }
275}
276
277@Entry
278@Component
279struct Index {
280  @State arr: number[] = [1,2,3];
281
282  build() {
283    Row() {
284      Column() {
285        Child({value: this.arr[0]})
286        Child({value: this.arr[1]})
287        Child({value: this.arr[2]})
288
289        Divider().height(5)
290
291        ForEach(this.arr,
292          (item: number) => {
293            Child({value: item})
294          },
295          (item: string) => item.toString()
296        )
297        Text('replace entire arr')
298        .fontSize(50)
299        .onClick(()=>{
300          // 两个数组都包含项“3”。
301          this.arr = this.arr[0] == 1 ? [3,4,5] : [1,2,3];
302        })
303      }
304    }
305  }
306}
307```
308
309
310初始渲染创建6个子组件实例,每个\@Prop装饰的变量初始化都在本地拷贝了一份数组项。子组件onclick事件处理程序会更改局部变量值。
311
312
313假设我们点击了多次,所有变量的本地取值都是“7”。
314
315
316
317```
3187
3197
3207
321----
3227
3237
3247
325```
326
327
328单击replace entire arr后,屏幕将显示以下信息。
329
330
331
332```
3333
3344
3355
336----
3377
3384
3395
340```
341
342
343- 在子组件Child中做的所有的修改都不会同步回父组件Index组件,所以即使6个组件显示都为7,但在父组件Index中,this.arr保存的值依旧是[1,2,3]。
344
345- 点击replace entire arr,this.arr[0] == 1成立,将this.arr赋值为[3, 4, 5];
346
347- 因为this.arr[0]已更改,Child({value: this.arr[0]})组件将this.arr[0]更新同步到实例\@Prop装饰的变量。Child({value: this.arr[1]})和Child({value: this.arr[2]})的情况也类似。
348
349
350- this.arr的更改触发ForEach更新,this.arr更新的前后都有数值为3的数组项:[3, 4, 5] 和[1, 2, 3]。根据diff机制,数组项“3”将被保留,删除“1”和“2”的数组项,添加为“4”和“5”的数组项。这就意味着,数组项“3”的组件不会重新生成,而是将其移动到第一位。所以“3”对应的组件不会更新,此时“3”对应的组件数值为“7”,ForEach最终的渲染结果是“7”,“4”,“5”。
351
352
353### 从父组件中的\@State类对象属性到\@Prop简单类型的同步
354
355如果图书馆有一本图书和两位用户,每位用户都可以将图书标记为已读,此标记行为不会影响其它读者用户。从代码角度讲,对\@Prop图书对象的本地更改不会同步给图书馆组件中的\@State图书对象。
356
357在此示例中,图书类可以使用\@Observed装饰器,但不是必须的,只有在嵌套结构时需要此装饰器。这一点我们会在[从父组件中的@State数组项到@Prop class类型的同步](#从父组件中的state数组项到prop-class类型的同步)说明。
358
359
360```ts
361class Book {
362  public title: string;
363  public pages: number;
364  public readIt: boolean = false;
365
366  constructor(title: string, pages: number) {
367    this.title = title;
368    this.pages = pages;
369  }
370}
371
372@Component
373struct ReaderComp {
374  @Prop book: Book = new Book("", 0);
375
376  build() {
377    Row() {
378      Text(this.book.title)
379      Text(`...has${this.book.pages} pages!`)
380      Text(`...${this.book.readIt ? "I have read" : 'I have not read it'}`)
381        .onClick(() => this.book.readIt = true)
382    }
383  }
384}
385
386@Entry
387@Component
388struct Library {
389  @State book: Book = new Book('100 secrets of C++', 765);
390
391  build() {
392    Column() {
393      ReaderComp({ book: this.book })
394      ReaderComp({ book: this.book })
395    }
396  }
397}
398```
399
400### 从父组件中的\@State数组项到\@Prop class类型的同步
401
402在下面的示例中,更改了\@State 修饰的allBooks数组中Book对象上的属性,但点击“Mark read for everyone”无反应。这是因为该属性是第二层的嵌套属性,\@State装饰器只能观察到第一层属性,不会观察到此属性更改,所以框架不会更新ReaderComp。
403
404```ts
405let nextId: number = 1;
406
407// @Observed
408class Book {
409  public id: number;
410  public title: string;
411  public pages: number;
412  public readIt: boolean = false;
413
414  constructor(title: string, pages: number) {
415    this.id = nextId++;
416    this.title = title;
417    this.pages = pages;
418  }
419}
420
421@Component
422struct ReaderComp {
423  @Prop book: Book = new Book();
424
425  build() {
426    Row() {
427      Text(this.book.title)
428      Text(`...has${this.book.pages} pages!`)
429      Text(`...${this.book.readIt ? "I have read" : 'I have not read it'}`)
430        .onClick(() => this.book.readIt = true)
431    }
432  }
433}
434
435@Entry
436@Component
437struct Library {
438  @State allBooks: Book[] = [new Book("100 secrets of C++", 765), new Book("Effective C++", 651), new Book("The C++ programming language", 1765)];
439
440  build() {
441    Column() {
442      Text('library`s all time favorite')
443      ReaderComp({ book: this.allBooks[2] })
444      Divider()
445      Text('Books on loaan to a reader')
446      ForEach(this.allBooks, (book: void) => {
447        ReaderComp({ book: book })
448      },
449        (book: number): number => book.id)
450      Button('Add new')
451        .onClick(() => {
452          this.allBooks.push(new Book("The C++ Standard Library", 512));
453        })
454      Button('Remove first book')
455        .onClick(() => {
456          this.allBooks.shift();
457        })
458      Button("Mark read for everyone")
459        .onClick(() => {
460          this.allBooks.forEach((book) => book.readIt = true)
461        })
462    }
463  }
464}
465```
466
467 需要使用\@Observed装饰class Book,Book的属性将被观察。 需要注意的是,\@Prop在子组件装饰的状态变量和父组件的数据源是单向同步关系,即ReaderComp中的\@Prop book的修改不会同步给父组件Library。而父组件只会在数值有更新的时候(和上一次状态的对比),才会触发UI的重新渲染。
468
469```ts
470@Observed
471class Book {
472  public id: number;
473  public title: string;
474  public pages: number;
475  public readIt: boolean = false;
476
477  constructor(title: string, pages: number) {
478    this.id = nextId++;
479    this.title = title;
480    this.pages = pages;
481  }
482}
483```
484
485\@Observed装饰的类的实例会被不透明的代理对象包装,此代理可以检测到包装对象内的所有属性更改。如果发生这种情况,此时,代理通知\@Prop,\@Prop对象值被更新。
486
487### \@Prop本地初始化不和父组件同步
488
489为了支持\@Component装饰的组件复用场景,\@Prop支持本地初始化,这样可以让\@Prop是否与父组件建立同步关系变得可选。当且仅当\@Prop有本地初始化时,从父组件向子组件传递\@Prop的数据源才是可选的。
490
491下面的示例中,子组件包含两个\@Prop变量:
492
493- \@Prop customCounter没有本地初始化,所以需要父组件提供数据源去初始化\@Prop,并当父组件的数据源变化时,\@Prop也将被更新;
494
495- \@Prop customCounter2有本地初始化,在这种情况下,\@Prop依旧允许但非强制父组件同步数据源给\@Prop。
496
497
498```ts
499@Component
500struct MyComponent {
501  @Prop customCounter: number = 0;
502  @Prop customCounter2: number = 5;
503
504  build() {
505    Column() {
506      Row() {
507        Text(`From Main: ${this.customCounter}`).width(90).height(40).fontColor('#FF0010')
508      }
509
510      Row() {
511        Button('Click to change locally !').width(180).height(60).margin({ top: 10 })
512          .onClick(() => {
513            this.customCounter2++
514          })
515      }.height(100).width(180)
516
517      Row() {
518        Text(`Custom Local: ${this.customCounter2}`).width(90).height(40).fontColor('#FF0010')
519      }
520    }
521  }
522}
523
524@Entry
525@Component
526struct MainProgram {
527  @State mainCounter: number = 10;
528
529  build() {
530    Column() {
531      Row() {
532        Column() {
533          Button('Click to change number').width(480).height(60).margin({ top: 10, bottom: 10 })
534            .onClick(() => {
535              this.mainCounter++
536            })
537        }
538      }
539
540      Row() {
541        Column() {
542          // customCounter必须从父组件初始化,因为MyComponent的customCounter成员变量缺少本地初始化;此处,customCounter2可以不做初始化。
543          MyComponent({ customCounter: this.mainCounter })
544          // customCounter2也可以从父组件初始化,父组件初始化的值会覆盖子组件customCounter2的本地初始化的值
545          MyComponent({ customCounter: this.mainCounter, customCounter2: this.mainCounter })
546        }
547      }
548    }
549  }
550}
551```
552
553### \@Prop嵌套场景
554
555在嵌套场景下,每一层都要用@Observed装饰,且每一层都要被@Prop接收,这样才能观察到嵌套场景。
556
557```ts
558// 以下是嵌套类对象的数据结构。
559@Observed
560class ClassA {
561  public title: string;
562
563  constructor(title: string) {
564    this.title = title;
565  }
566}
567
568@Observed
569class ClassB {
570  public name: string;
571  public a: ClassA;
572
573  constructor(name: string, a: ClassA) {
574    this.name = name;
575    this.a = a;
576  }
577}
578```
579
580以下组件层次结构呈现的是@Prop嵌套场景的数据结构。
581
582```ts
583
584@Entry
585@Component
586struct Parent {
587  @State votes: ClassB = new ClassB('Hello', new ClassA('world'))
588
589  build() {
590    Column() {
591      Button('change')
592        .onClick(() => {
593          this.votes.name = "aaaaa"
594          this.votes.a.title = "wwwww"
595        })
596      Child({ vote: this.votes })
597    }
598
599  }
600}
601
602@Component
603struct Child {
604  @Prop vote: ClassB = new ClassB('', new ClassA(''));
605  build() {
606    Column() {
607
608      Text(this.vote.name).fontSize(36).fontColor(Color.Red).margin(50)
609        .onClick(() => {
610          this.vote.name = 'Bye'
611        })
612      Text(this.vote.a.title).fontSize(36).fontColor(Color.Blue)
613        .onClick(() => {
614          this.vote.a.title = "openHarmony"
615        })
616      Child1({vote1:this.vote.a})
617
618    }
619  }
620}
621
622@Component
623struct Child1 {
624  @Prop vote1: ClassA = new ClassA('');
625  build() {
626    Column() {
627      Text(this.vote1.title).fontSize(36).fontColor(Color.Red).margin(50)
628        .onClick(() => {
629          this.vote1.title = 'Bye Bye'
630        })
631    }
632  }
633}
634```
635
636## Prop支持联合类型实例
637
638@Prop支持联合类型和undefined和null,在下面的示例中,count类型为ClassA | undefined,点击父组件Library中的Button改变count的属性或者类型,Child中也会对应刷新。
639
640```ts
641class Animals {
642  public name: string;
643
644  constructor(name: string) {
645    this.name = name;
646  }
647}
648
649@Component
650struct Child {
651  @Prop animal: Animals | undefined;
652
653  build() {
654    Column() {
655      Text(`Child's animal is  ${this.animal instanceof Animals ? this.animal.name : 'undefined'}`).fontSize(30)
656
657      Button('Child change animals into tigers')
658        .onClick(() => {
659          // 赋值为Animals的实例
660          this.animal = new Animals("Tiger")
661        })
662
663      Button('Child change animal to undefined')
664        .onClick(() => {
665          // 赋值为undefined
666          this.animal = undefined
667        })
668
669    }.width('100%')
670  }
671}
672
673@Entry
674@Component
675struct Library {
676  @State animal: Animals | undefined = new Animals("lion");
677
678  build() {
679    Column() {
680      Text(`Parents' animals are  ${this.animal instanceof Animals ? this.animal.name : 'undefined'}`).fontSize(30)
681
682      Child({animal: this.animal})
683
684      Button('Parents change animals into dogs')
685        .onClick(() => {
686          // 判断animal的类型,做属性的更新
687          if (this.animal instanceof Animals) {
688            this.animal.name = "Dog"
689          } else {
690            console.info('num is undefined, cannot change property')
691          }
692        })
693
694      Button('Parents change animal to undefined')
695        .onClick(() => {
696          // 赋值为undefined
697          this.animal = undefined
698        })
699    }
700  }
701}
702```
703
704<!--no_check-->