HarmonyOS Next 状态管理:Event 装饰器实践

95 阅读3分钟

目录

一. @Event 修饰器概述

在日常开发中,父子组件之间的数据同步是一个常见需求。虽然可以通过 @Param 结合回调函数实现父子组件的同步刷新,但这种方式较为繁琐。为此,@Event 修饰器应运而生,专门用于简化事件传递和数据同步。

二、@Event 修饰器的限制

使用范围:
- @Event 只能在 ComponentV2 中使用。
修饰范围
- @Event只能修饰回调方法,不能与其他变量搭配使用。相比之下,@Param 既可以修饰回调方法,也可以修饰变量。

三、实践探索

3.1 @Event的简单使用


@Entry
@ComponentV2
struct Index {
  @Local msg: string = "x"

  build() {
    Column({space: 20}) {
      Text(this.msg)
      Button('change value')
        .onClick(() => {
          this.msg += `abc`
        })
      Line().width('100%').height(1).backgroundColor(Color.Gray)
      ChildComponent({cMsg: this.msg, changeValueCallback: () => {
        this.msg += `${Math.round(Math.random() * 100)}`
      }, changeMsgCallback: (msg: string) => {
        this.msg = msg
      }})
    }
  }
}

@ComponentV2
struct ChildComponent {
  @Param cMsg: string = ""
  @Event changeValueCallback: () => void
  @Event changeMsgCallback: (msg: string) => void

  build() {
    Column({space: 12}) {
      Text(this.cMsg)
      Button('调用changeValueCallback')
        .onClick(() => {
          this.changeValueCallback()
        })
      Button('调用changeMsgCallbackk')
        .onClick(() => {
          this.changeMsgCallback(`${Date().toString()}`)
        })
    }
  }
}

录屏2025-03-02 19.09.28.gif

关键点

  • 回调方法的使用:子组件无法直接修改 cMsg 的值,但可以通过 @Event 修饰的回调方法间接修改父组件的状态。
  • 事件传递@Event 提供了一种简洁的方式,用于在父子组件之间传递事件并同步数据。

3.2 @Event 装饰可选方法

@Event同样可以装饰可选方法,例子如下:

@Entry
@ComponentV2
struct Index {
  @Local name: string = "name"

  build() {
    Column({space: 20}) {
      Text(this.name)
      Line().width('100%').height(1).backgroundColor(Color.Gray)
      ChildComponent({cName: this.name, changeNameCallback: (name: string) => {
        this.name = name
      }})
    }
  }
}

@ComponentV2
struct ChildComponent {
  @Param cName: string = "cName"
  @Event changeNameCallback?: (name: string) => void

  build() {
    Column({space: 12}) {
      Text(`cName:${this.cName}`)
        .onClick(() => {
          this.changeNameCallback!(`${Date().toString()}`)
        })
    }
  }
}

关键点

  • 可选回调@Event 可以修饰可选回调方法,增强了代码的灵活性。
  • 空值处理:在调用可选回调方法时,需确保其存在(如使用 ! 强制解包)。

3.3 @Event 更新父子组件时机

@Entry
@ComponentV2
struct Index {
  @Local name: string = "name"

  build() {
    Column({space: 20}) {
      Text(this.name)
      Line().width('100%').height(1).backgroundColor(Color.Gray)
      ChildComponent({cName: this.name, changeNameCallback: (name: string) => {
        this.name = name
        console.log(`callback called in father component:${this.name}`)
      }})
    }
  }
}

@ComponentV2
struct ChildComponent {
  @Param cName: string = "cName"
  @Event changeNameCallback?: (name: string) => void

  build() {
    Column({space: 12}) {
      Text(`cName:${this.cName}`)
        .onClick(() => {
          if (this.changeNameCallback) {
            this.changeNameCallback(`${Date().toString()}`)
            console.log(`callback called in subcomponent: ${this.cName}`)
          }
        })
    }
  }
}

录屏2025-03-02 19.28.56.gif

控制台输出

callback called in father component:Sun Mar 02 2025 09:39:27 GMT+0800
callback called in subcomponent: name

关键点

  • 同步机制:通过 @Event 修饰的回调方法修改父组件的值是立即生效的,但从父组件同步回子组件的过程是异步的。因此,在调用 @Event 方法后,子组件中的值不会立即更新。
  • 异步更新:这种设计避免了频繁的同步操作,提升了性能,但开发者需注意数据更新的时机。

四、总结

通过以上实践,我们可以得出以下结论:

  1. 事件传递@Event 提供了一种简洁的方式,用于在父子组件之间传递事件并同步数据。
  2. 灵活性@Event 支持修饰可选回调方法,增强了代码的灵活性。
  3. 异步更新:父组件状态的更新是立即生效的,但子组件的更新是异步的,开发者需注意数据同步的时机。

@Event 修饰器的引入,极大地简化了父子组件之间的数据同步和事件传递,提升了代码的可读性和可维护性。在实际开发中,合理使用 @Event 可以有效减少冗余代码,提高开发效率。