Skip to content

装饰器V2

@Track装饰器:class对象属性级更新

TIP

@Track应用于class对象的属性级更新。@Track装饰的属性变化时,只会触发该属性关联的UI更新

WARNING

使用场景:嵌套类、继承类、@Trace装饰基础类型数据、对象数据、Map类型、Set类型、Date类型

javascript
class CaseModelOne {
  @Track str1: string = 'CaseModelOne_str1'
  @Track str2: string = 'CaseModelOne_str2'
}

class CaseModelTwo {
  str1: string = 'CaseModelTwo_str1'
  str2: string = 'CaseModelTwo_str2'
}

/**
 * CaseModelOne ------> 被@Track装饰的 对象的数据和状态装饰器绑定,修改对应的属性不会触发其他的组件刷新
 *
 * CaseModelTwo ------> 不被@Track装饰的 修改某一个对象属性值 会刷新整个使用CaseModelTwo下的属性值相关的组件
 *
 *
 * 类LogTrack中的属性均被@Track装饰器装饰,点击按钮"change caseModelOne.str1",此时Text1刷新,Text2不刷新,只有一条日志输出,避免了冗余刷新。
 * Text 1 is rendered
 *
 * 类logNotTrack中的属性均未被@Track装饰器装饰,点击按钮"change caseModelTwo.str1",此时Text3、Text4均会刷新,有两条日志输出,存在冗余刷新。
 * Text 3 is rendered
 * Text 4 is rendered
 */

@Entry
@ComponentV2
struct TrackCase {
  @Local caseModelOne: CaseModelOne = new CaseModelOne()
  @Local caseModelTwo: CaseModelTwo = new CaseModelTwo()

  isRender(index: number) {
    console.log(`Text ${index} is rendered`);
    return ''
  }

  build() {
    Row() {
      Column() {
        Text(this.caseModelOne.str1)
          .fontWeight(FontWeight.Bold)
          .fontSize(this.isRender(1))
        Text(this.caseModelOne.str2)
          .fontWeight(FontWeight.Bold)
          .fontSize(this.isRender(2))

        Button('change caseModelOne.str1')
          .onClick(() => {
            this.caseModelOne.str1 = 'caseModelOne'
          })

        Text(this.caseModelTwo.str1)
          .fontWeight(FontWeight.Bold)
          .fontSize(this.isRender(3))
        Text(this.caseModelTwo.str2)
          .fontWeight(FontWeight.Bold)
          .fontSize(this.isRender(4))

        Button('change caseModelTwo.str1')
          .onClick(() => {
            this.caseModelTwo.str1 = 'caseModelTwo'
          })
      }
      .width('100%')
    }
    .height('100%')
  }
}

@ObservedV2装饰器和@Trace装饰器

TIP

@ObservedV2和@Trace提供了对嵌套类对象属性变化直接观测的能力,是状态管理V2中相对核心的能力之一

WARNING

使用场景:嵌套类、继承类、@Trace装饰基础类型数据、对象数据、Map类型、Set类型、Date类型

javascript
/** 嵌套类型*/
@ObservedV2
class CaseModelOne {
  str1: CaseModelThree = new CaseModelThree()
}

/** 继承类型*/
@ObservedV2
class CaseModelTwo {
  @Trace str1: string = 'CaseModelTwo_原始'
}
class CaseModelTwoSon extends CaseModelTwo{
  getStr() {
    this.str1 = 'CaseModelTwoSon_更新'
    return this.str1
  }
}

/** 基础类型*/
@ObservedV2
class CaseModelThree {
  @Trace str1: string = 'CaseModelThree_原始'
}

/** 对象数组类型*/
@ObservedV2
class CaseModelFour {
  @Trace str1?: string = 'CaseModelFour_原始'

  constructor(name?: string) {
    this.str1 = name
  }
}
@ObservedV2
class CaseModelFourArray {
  @Trace caseModelFourArray: CaseModelFour[] = [new CaseModelFour(), new CaseModelFour(), new CaseModelFour(), new CaseModelFour()]
}

/** Map类型*/
@ObservedV2
class CaseModelFive {
  @Trace caseModelFiveMap: Map<number, string> = new Map([[0, "a"], [1, "b"], [3, "c"]]);
}

/** Set类型*/
@ObservedV2
class CaseModelSix {
  @Trace caseModelSixSet: Set<string> = new Set(['0', '1', '2', '3'])
}

/** Date类型*/
@ObservedV2
class CaseModelSeven {
  @Trace CaseModelSevenDate: Date = new Date('2021-08-08')
}


@Entry
@ComponentV2
struct ObservedV2AndTrace {
  private caseModelOne: CaseModelOne = new CaseModelOne()
  private caseModelTwoSon: CaseModelTwoSon = new CaseModelTwoSon()
  private caseModelThree: CaseModelThree = new CaseModelThree()
  private caseModelFourArray: CaseModelFourArray = new CaseModelFourArray()
  private caseModelFive: CaseModelFive = new CaseModelFive()
  private caseModelSix: CaseModelSix = new CaseModelSix()
  private caseModelSeven: CaseModelSeven = new CaseModelSeven()

  build() {
    Row() {
      Column() {
        Text(this.caseModelOne.str1.str1)
          .fontWeight(FontWeight.Bold)
        Text(this.caseModelTwoSon.str1)
          .fontWeight(FontWeight.Bold)
        Text(this.caseModelThree.str1)
          .fontWeight(FontWeight.Bold)
        Text(this.caseModelFourArray.caseModelFourArray[0].str1)
          .fontWeight(FontWeight.Bold)
        Text(this.caseModelFive.caseModelFiveMap[0])
          .fontWeight(FontWeight.Bold)
        Text(`${this.caseModelSix.caseModelSixSet.values()}`)
          .fontWeight(FontWeight.Bold)
        Text(`${this.caseModelSeven.CaseModelSevenDate}`)
          .fontWeight(FontWeight.Bold)

        Button('change all value')
          .onClick(() => {
            this.caseModelOne.str1.str1 = 'caseModelOne_更新'
            this.caseModelTwoSon.getStr()
            this.caseModelThree.str1 = 'caseModelThree_更新'
            this.caseModelFourArray.caseModelFourArray[0] = new CaseModelFour('caseModelFourArray_更新')
            this.caseModelFive.caseModelFiveMap[0] = 'caseModelFiveMap_更新'
            this.caseModelSix.caseModelSixSet = new Set(['4', '5', '6', '7']);
            this.caseModelSeven.CaseModelSevenDate = new Date('2021-10-08')
          })
      }
      .width('100%')
    }
    .height('100%')
  }
}

@ComponentV2装饰器:自定义组件

TIP

为了在自定义组件中使用V2版本状态变量装饰器的能力.开发者可以使用@ComponentV2装饰器装饰自定义组件

javascript
@ComponentV2 // 装饰器
struct Index { // struct声明的数据结构
  build() { // build定义的UI
  }
}

@Local装饰器:组件内部状态

TIP

为了实现对@ComponentV2装饰的自定义组件中变量变化的观测,开发者可以使用@Local装饰器装饰变量

WARNING

使用场景:观察对象整体变化、装饰Date类型变量、Map类型变量、Set类型变量、联合类型

javascript
/** 观测对象整体变化*/
@ObservedV2
class CaseModelOne {
  @Trace str1: string = 'CaseModelOne_str1'
}

/** Map类型*/
@ObservedV2
class CaseModelTwo {
  @Trace caseModelFiveMap: Map<number, string> = new Map([[0, "a"], [1, "b"], [3, "c"]])
}

/** Set类型*/
@ObservedV2
class CaseModelThree {
  @Trace caseModelSixSet: Set<string> = new Set(['0', '1', '2', '3'])
}

/** Date类型*/
@ObservedV2
class CaseModelFour {
  @Trace CaseModelSevenDate: Date = new Date('2021-08-08')
}

@Entry
@ComponentV2
struct LocalCase {
  @Local caseModelOne: CaseModelOne = new CaseModelOne()
  @Local caseModelTwo: CaseModelTwo = new CaseModelTwo()
  @Local caseModelThree: CaseModelThree = new CaseModelThree()
  @Local caseModelFour: CaseModelFour = new CaseModelFour()

  build() {
    Row() {
      Column() {
        Text(this.caseModelOne.str1)
          .fontWeight(FontWeight.Bold)
        Text(`${this.caseModelTwo.caseModelFiveMap.values()}`)
          .fontWeight(FontWeight.Bold)
        Text(`${this.caseModelThree.caseModelSixSet}`)
          .fontWeight(FontWeight.Bold)
        Text(`${this.caseModelFour.CaseModelSevenDate}`)
          .fontWeight(FontWeight.Bold)

        Button('change all value')
          .onClick(() => {
            this.caseModelOne.str1 = 'caseModelOne'
            this.caseModelTwo.caseModelFiveMap.set(0, '2222')
            this.caseModelThree.caseModelSixSet = new Set(['0', '1', '2', '3'])
            this.caseModelFour.CaseModelSevenDate = new Date('2021-22-11')
          })

      }
      .width('100%')
    }
    .height('100%')
  }
}

@Param:组件外部输入

TIP

为了增强子组件接受外部参数输入的能力.开发者可以使用@Param装饰器

WARNING

使用场景:从父组件到子组件变量与同步、装饰Date类型变量、Map类型变量、Set类型变量、联合类型

javascript
/** 基础类型*/
@ObservedV2
class CaseModelOne {
  @Trace str1: string = 'CaseModelSix_原始'
}

/** Map类型*/
@ObservedV2
class CaseModelTwo {
  @Trace caseModelFiveMap: Map<number, string> = new Map([[0, "a"], [1, "b"], [3, "c"]])
}

/** Set类型*/
@ObservedV2
class CaseModelThree {
  @Trace caseModelSixSet: Set<string> = new Set(['0', '1', '2', '3'])
}

/** Date类型*/
@ObservedV2
class CaseModelFour {
  @Trace CaseModelSevenDate: Date = new Date('2021-08-08')
}



@Entry
@ComponentV2
struct ParamCase {
  @Local caseModelOne: CaseModelOne = new CaseModelOne()
  @Local caseModelTwo: CaseModelTwo = new CaseModelTwo()
  @Local caseModelThree: CaseModelThree = new CaseModelThree()
  @Local caseModelFour: CaseModelFour = new CaseModelFour()

  build() {
    Column() {
        ParamCaseSon({
          caseModelOne: this.caseModelOne,
          caseModelTwo: this.caseModelTwo,
          caseModelThree: this.caseModelThree,
          caseModelFour: this.caseModelFour,
        })

      Button("change")
        .onClick(() => {
          this.caseModelOne.str1 = 'caseModelOne_更新'
          this.caseModelTwo.caseModelFiveMap.set(0,'更新')
          this.caseModelThree.caseModelSixSet = new Set(['更新'])
          this.caseModelFour.CaseModelSevenDate = new Date('2021-2-22')
        })
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
}

/**
 * 自组件,Require标识,必传参数
 */
@ComponentV2
struct ParamCaseSon {
  @Require @Param caseModelOne: CaseModelOne
  @Require @Param caseModelTwo: CaseModelTwo
  @Require @Param caseModelThree: CaseModelThree
  @Require @Param caseModelFour: CaseModelFour
  build() {
    Column() {
      Text(this.caseModelOne.str1)
      Text(this.caseModelTwo.caseModelFiveMap.get(0))
      Text(`${this.caseModelThree.caseModelSixSet}`)
      Text(`${this.caseModelFour.CaseModelSevenDate}`)
    }
  }
}

@Once:初始化同步一次

TIP

为了实现仅从外部初始化一次、不接受后续同步变化的能力.开发者可以使用@Once装饰器搭配@Param装饰器使用

WARNING

使用场景:变量仅初始化同步一次、本地修改@Param变量

javascript
@Entry
@ComponentV2
struct OnceCase {
  @Local name: string = "xiaoxiao"

  build() {
    Column() {
      Text(`name: ${this.name}`)
      Button("change name")
        .onClick(() => {
          this.name = "dada";
        })
      OnceCaseSon({ name: this.name })
    }
  }
}

@ComponentV2
struct OnceCaseSon {
  @Param @Once name: string = ""

  build() {
    Column() {
      Text(`onceParam: ${this.name}`)
      Button("change name")
        // @Once与@Param搭配使用时,可以在本地修改@Param变量的值。
        .onClick(() => {
          this.name = 'honhon'
        })
    }
  }
}

@Event装饰器:规范组件输出

TIP

为了实现子组件向父组件要求更新@Param装饰变量的能力.开发者可以使用@Event装饰器。使用@Event装饰回调方法是一种规范.表明子组件需要传入更新数据源的回调

WARNING

使用场景:更改父组件中变量

javascript
@Entry
@ComponentV2
struct EventCase {
  @Local name: string = "xiaoxiao"

  build() {
    Column() {
      Text(`name: ${this.name}`)
      EventCaseSon({ changeEventCaseName: () => this.name = 'EventCaseSon' })
    }
  }
}

@ComponentV2
struct EventCaseSon {
  @Event changeEventCaseName: () => void = () => {}

  build() {
    Column() {
      Button("changeEventCaseName")// @Once与@Param搭配使用时,可以在本地修改@Param变量的值。
        .onClick(() => this.changeEventCaseName())
    }
  }
}

@Provider装饰器和@Consumer装饰器:跨组件层级双向同步

TIP

为了实现子组件向父组件要求更新@Param装饰变量的能力.开发者可以使用@Event装饰器。使用@Event装饰回调方法是一种规范.表明子组件需要传入更新数据源的回调

javascript
/**
 * @Provider和@Consumer可以装饰回调事件,用于组件之间完成行为抽象
 *
 * @Provider和@Consumer装饰复杂类型,配合@Trace一起使用
 *
 * !!! @Provider重名时,@Consumer向上查找其最近的@Provider
 *
 * 在子组件受用父组件用@Consumer获取的值会刷新或者初始化@Param装饰的值
 *
 */

@Entry
@ComponentV2
struct ProviderAndProviderCase {
  @Provider('name') name: string = '史迪黄'

  build() {
    Column() {
      ProviderAndProviderSon()
    }
  }
}

@ComponentV2
struct ProviderAndProviderSon {
  @Consumer('name') name: string = ''
  //  如果未使用别名绑定将使用默认值进行显示
  @Consumer('') age: number = 0

  build() {
    Column() {
      Text(`form father value${this.name}`)
        .onClick(() => {
          this.name = '小小黄'
        })
      Text(`my age is${this.age}`)

      // <---------------------->
      ProviderAndProviderParam({ name: this.name })
    }
    .size({ width: '100%', height: '100%' })
  }
}

@ComponentV2
struct ProviderAndProviderParam {
  @Param @Require name: string

  build() {
    Column() {
      Text(`form ProviderAndProviderSon value${this.name}`)
    }
    .size({ width: '100%', height: '100%s' })
  }
}

@Monitor装饰器:状态变量修改监听

TIP

为了增强状态管理框架对状态变量变化的监听能力.开发者可以使用@Monitor装饰器对状态变量进行监听

WARNING

监听深层属性变化

javascript
/**
 * @Monitor监听的变量需要被@Local、@Param、@Provider、@Consumer、@Computed装饰
 *
 * @Monitor监听的状态变量为类对象时,仅能监听对象整体的变化。监听类属性的变化需要类属性被@Trace装饰
 *
 * @Monitor能够监听数组长度变化=========>@Monitor("Array.length")
 *
 * @Monitor能够监听对象属性变化=========>@Monitor("类明.属性名")
 */
import { promptAction } from '@kit.ArkUI'

@ObservedV2
class CaseModelOne {
  @Trace name: string = 'CaseModelOne_原始'

  @Monitor("name")
  nameChange() {
    promptAction.showToast({ message: `在类中name监听到变化类 变化值 ====>: ${this.name}` })
  }
}

@Entry
@ComponentV2
struct MonitorCase {
  @Local name: string = "史迪黄"
  @Local age: number = 24
  @Local caseModelOneName: CaseModelOne = new CaseModelOne()

  @Monitor("name", "age", "caseModelOneName.name")
  onStrChange(monitor: IMonitor) {
    monitor.dirty.forEach((path: string) => {
      console.log(`${path} changed from ${monitor.value(path)?.before} to ${monitor.value(path)?.now}`)
    })
  }

  build() {
    Column() {
      Text(this.caseModelOneName.name)

      Button("change caseModelOneName")
        .onClick(() => this.caseModelOneName.name = "CaseModelOne_更新")


      Button("change this.name")
        .onClick(() => this.name = "史迪蓝")

      Button("change this.age")
        .onClick(() => this.age = 23)
    }
  }
}

@Computed装饰器:计算属性

TIP

在被计算的值变化的时候,只会计算一次。主要应用于解决UI多次重用该属性从而重复计算导致的性能问题

WARNING

使用场景:当被计算的属性变化时,@Computed装饰的getter访问器只会被求解一次、@Computed装饰的属性可以被@Monitor监听变化、@Computed装饰的属性可以初始化@Param

javascript

/**
 * 当被计算的属性变化时,@Computed装饰的getter访问器只会被求解一次
 *
 * @Computed装饰的属性可以被@Monitor监听变化
 *
 * @Computed装饰的属性可以初始化@Param
 */
@Entry
@ComponentV2
struct ComputedCase {
  @Local count: number = 100;

  @Computed
  get double() {
    return String(this.count * 2)
  }

  build() {
    Scroll() {
      Column({ space: 3 }) {
        Text(this.double)
        Text(this.double)
      }
    }
  }
}

@Type装饰器:标记类属性的类型

TIP

为了实现序列化类时不丢失属性的复杂类型.开发者可以使用@Type装饰器装饰类属性

WARNING

使用场景:持久化数据。

javascript

AppStorageV2: 应用全局UI状态存储

TIP

为了增强状态管理框架对应用全局UI状态变量存储的能力,开发者可以使用AppStorageV2存储应用全局UI状态变量数据

WARNING

使用场景:在两个页面之间存储数据

javascript
import { AppStorageV2, promptAction, router } from '@kit.ArkUI'
import { modelAll } from '../modelAll/modelAll'


/**
 * connect:创建或获取储存的数据
 *
 * remove:删除指定key的储存数据
 *
 * keys:返回所有AppStorageV2中的key
 */

// 子页面
@Entry
@ComponentV2
export struct AppStorageV2Son {
  @Local prop: modelAll = AppStorageV2.connect(modelAll, () => new modelAll())!

  build() {
    Column({ space: 10 }) {
      Text(this.prop.p1.toString())

      Button('改变modelAll下的p1数据').onClick((event: ClickEvent) => {
        this.prop.p1 = 10000000
      })

      Button('删除指定数据').onClick((event: ClickEvent) => {
        this.prop.p1 = 0
        AppStorageV2.remove(modelAll)
      })

      Button('返回所有AppStorageV2,key').onClick((event: ClickEvent) => {
        promptAction.showToast({ message: `${AppStorageV2.keys()}` })
      })


      Button('跳转').onClick((event: ClickEvent) => {
        router.pushUrl({ url: 'otherDir/AppStorageV2SonPage' })
      })
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
}


import { AppStorageV2, router } from '@kit.ArkUI'
import { modelAll } from '../modelAll/modelAll'
// 夫页面
@Entry
@ComponentV2
export struct AppStorageV2SonPage {
  @Local prop: modelAll = AppStorageV2.connect(modelAll, () => new modelAll())!

  build() {
    Column({ space: 10 }) {
      Text(this.prop.p1.toString())

      Button('返回').onClick((event: ClickEvent) => {
        router.pushUrl({ url: 'otherDir/AppStorageV2' })
      })
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
}

@ObservedV2
export class modelAll {
  @Trace p1: number = 0
  @Trace p2: number = 10
}

PersistenceV2: 持久化储存UI状态

TIP

为了增强状态管理框架对持久化存储UI的能力,开发者可以使用PersistenceV2存储持久化的数据

WARNING

使用场景:在两个页面之间存储数据

javascript
import { PersistenceV2 } from '@kit.ArkUI';
import { modelAll } from '../modelAll/modelAll';

// 接受序列化失败的回调
PersistenceV2.notifyOnError((key: string, reason: string, msg: string) => {
  console.error(`error key: ${key}, reason: ${reason}, message: ${msg}`)
});


/**
 * 为了增强状态管理框架对持久化存储UI的能力,开发者可以使用PersistenceV2存储持久化的数据。
 *
 * PersistenceV2提供状态变量持久化能力,开发者可以通过connect绑定同一个key,在状态变量变换和应用冷启动时,实现持久化能力。
 */

@Entry
@ComponentV2
struct PersistenceV2Case {
  @Local prop: modelAll = PersistenceV2.connect(modelAll, () => new modelAll())!

  build() {
    Column() {
      Button('点击:connect')
        .onClick(() => this.prop = PersistenceV2.connect(modelAll, 'Sample', () => new modelAll())!)

      Button('点击:remove')
        .onClick(() => PersistenceV2.remove(modelAll))

      Button('点击:save')
        .onClick(() => PersistenceV2.save(modelAll))

      Text(`Page1 add 1 to prop.p1: ${this.prop.p1}`)
        .fontSize(30)
        .onClick(() => this.prop.p1++)

      Text(`Page1 add 1 to prop.p2: ${this.prop.p1}`)
        .fontSize(30)
        .onClick(() => this.prop.p1++)

      // 获取当前PersistenceV2里面的所有key
      Text(`all keys in PersistenceV2: ${PersistenceV2.keys()}`)
        .fontSize(30)
    }
  }
}

@ObservedV2
export class modelAll {
  @Trace p1: number = 0
  @Trace p2: number = 10
}

!!语法:双向绑定

TIP

在状态管理V1中使用$$用于内置组件双向绑定

WARNING

使用场景:自定义组件间双向绑定,内置组件参数双向绑定

javascript
/**
 * !!语法糖作为统一处理双向绑定语法。
 *
 * !!双向绑定语法不支持多层父子组件传递。
 */
@Entry
@ComponentV2
struct TwoWayCase {
  @Local value: number = 0;

  build() {
    Column() {
      Text(`${this.value}`)
      Button(`change value`).onClick(() => {
        this.value++;
      })
      TwoWayCaseSon({ value: this.value!! })

      // 双向绑定语法糖可视为:
      TwoWayCaseSon({
        value: this.value, $value: (val: number) => {
          this.value = val
        }
      })

    }
  }
}

@ComponentV2
struct TwoWayCaseSon {
  @Param value: number = 0;
  @Event $value: (val: number) => void = () => {
  }

  build() {
    Column() {
      Text(`${this.value}`)
      Button(`change value `).onClick(() => this.$value(10))
    }
  }
}

自定义组件冻结功能

TIP

当@ComponentV2装饰的自定义组件处于非激活状态时,状态变量将不响应更新,即@Monitor不会调用,状态变量关联的节点不会刷新

WARNING

使用场景:页面路由,TabContent,Navigation

javascript
/**
 * 支持的场景有:页面路由,TabContent,Navigation。
 */

// 自定义组件冻结功能
@Entry
@ComponentV2
struct FreezeCase {
  @Local message: number = 0;
  @Local data: number[] = [0, 1];

  build() {
    Row() {
      Column() {
        Button('change message').onClick(() => {
          this.message++;
        })

        Tabs() {
          ForEach(this.data, (item: number) => {
            TabContent() {
              FreezeCaseSon({ message: this.message, index: item })
            }.tabBar(`tab${item}`)
          }, (item: number) => item.toString())
        }
      }
      .width('100%')
    }
    .height('100%')
  }
}

@ComponentV2({ freezeWhenInactive: true })
struct FreezeCaseSon {
  @Param message: number = 0;
  @Param index: number = 0;

  @Monitor('message') onMessageUpdated(mon: IMonitor) {
    console.info(`FreezeChild message callback func ${this.message}, index: ${this.index}`);
  }

  build() {
    Text("message" + `${this.message}, index: ${this.index}`)
      .fontSize(50)
      .fontWeight(FontWeight.Bold)
  }
}

Repeat:子组件复用

TIP

Repeat基于数据源进行循环渲染,需要与容器组件配合使用,且接口返回的组件应当是允许包含在Repeat父容器组件中的子组件

WARNING

使用场景:non-virtualScroll数据展示&操作,virtualScroll数据展示&操作,Repeat嵌套,父容器组件应用场景:与List组合使用,与Grid组合使用,与Swiper组合使用

javascript
/**
 * non-virtualScroll模式和virtualScroll模式。
 *
 * non-virtualScroll模式:适合短数据列表/组件全部加载的场景。
 *
 * virtualScroll模式(开启virtualScroll开关):Repeat根据容器组件的有效加载范围(可视区域+预加载区域) 加载子组件。
 *
 * non-virtualScroll 仅作为数据改变-Repeat会复用之前的组件
 *
 */

@Entry
@ComponentV2
struct RepeatCase {
  @Local simpleList: Array<string> = ['one', 'two', 'three'];

  build() {
    Row() {
      Column() {
        Text('点击修改第3个数组项的值')
          .fontSize(24)
          .fontColor(Color.Red)
          .onClick(() => {
            this.simpleList[2] = 'new three';
          })

        Repeat<string>(this.simpleList)
          .each((obj: RepeatItem<string>)=>{
            RepeatCaseSon({ item: obj.item })
              .margin({top: 20})
          })
          .key((item: string) => item)
      }
      .justifyContent(FlexAlign.Center)
      .width('100%')
      .height('100%')
    }
    .height('100%')
    .backgroundColor(0xF1F3F5)
  }
}

@ComponentV2
struct RepeatCaseSon {
  @Param @Require item: string;

  build() {
    Text(this.item)
      .fontSize(30)
  }
}