深入解析ArkTS状态管理:@Watch与$$运算符的精妙应用

举报
柠檬味拥抱 发表于 2023/11/30 00:59:18 2023/11/30
【摘要】 @[toc] ArkTS 状态管理深度解析:@Watch 和 $$ 运算符的妙用在 ArkTS 的开发文档中,我们不仅可以发现强大的组件状态管理和应用状态管理,还能看到一些高级功能,其中包括 @Watch 装饰器和 $$ 运算符。这两者为开发者提供了更多的控制权和便利性。 @Watch 装饰器:状态变量的敏感监听@Watch 装饰器在 ArkUI 框架中扮演了状态变量变化的守望者角色。当状态...

@[toc]

ArkTS 状态管理深度解析:@Watch 和 $$ 运算符的妙用

在 ArkTS 的开发文档中,我们不仅可以发现强大的组件状态管理和应用状态管理,还能看到一些高级功能,其中包括 @Watch 装饰器和 $$ 运算符。这两者为开发者提供了更多的控制权和便利性。

@Watch 装饰器:状态变量的敏感监听

@Watch 装饰器在 ArkUI 框架中扮演了状态变量变化的守望者角色。当状态变量发生变化时,@Watch 的回调方法将被调用。需要注意的是,@Watch 使用的是严格相等(===)的判断方式,确保精准捕捉到状态的变化。

装饰器说明

@Watch 不仅是一个装饰器,更是一个变量的监听器。以下是一些关键点:

  • 装饰器参数:回调函数的引用,用于处理状态变量的变化。
  • 可装饰的自定义组件变量:允许监听所有装饰器装饰的状态变量,但不允许监听常规变量。
  • 装饰器的顺序:建议将 @State、@Prop、@Link 等装饰器放在 @Watch 装饰器之前。
    在这里插入图片描述

语法说明

@Watch((changedPropertyName?: string) => void)
  • changedPropertyName 是被 watch 的属性名。
  • 在多个状态变量绑定同一个 @Watch 的回调方法时,可以通过 changedPropertyName 进行不同的逻辑处理。

观察变化和行为表现

@Watch 方法在自定义组件的属性变更之后同步执行。以下是一些关键观察和行为表现:

  • 当观察到状态变量的变化时,对应的 @Watch 的回调方法将被触发。
  • 如果在 @Watch 的方法里改变了其他的状态变量,也会引起状态变更和 @Watch 的执行。
  • 在第一次初始化的时候,@Watch 装饰的方法不会被调用,即认为初始化不是状态变量的改变。只有在后续状态改变时,才会调用 @Watch 回调方法。

限制条件

虽然 @Watch 提供了强大的状态监听能力,但是在使用时需要注意一些限制条件:

  • 建议避免无限循环,即不要在 @Watch 的回调方法里直接或者间接地修改同一个状态变量,以避免循环触发。
  • 关注性能,回调函数应仅执行快速运算,因为属性值更新函数会延迟组件的重新渲染。
  • 不建议在 @Watch 函数中调用 async/await,因为 @Watch 设计的用途是为了快速的计算,异步行为可能会导致重新渲染速度的性能问题。
    在这里插入图片描述

使用场景

@Watch 可以与自定义组件更新紧密配合,下面是一个示例,演示了组件更新和 @Watch 的处理步骤:

@Component
struct TotalView {
  @Prop @Watch('onCountUpdated') count: number;
  @State total: number = 0;

  // @Watch callback
  onCountUpdated(propName: string): void {
    this.total += this.count;
  }

  build() {
    Text(`Total: ${this.total}`)
  }
}

@Entry
@Component
struct CountModifier {
  @State count: number = 0;

  build() {
    Column() {
      Button('add to basket')
        .onClick(() => {
          this.count++
        })
      TotalView({ count: this.count })
    }
  }
}

在这个例子中,当 CountModifier 组件的按钮被点击时,@State count 变量增加,触发了 TotalView 组件的 @Watch 回调方法,更新了 TotalView 中的 total 变量。

$$ 运算符:内置组件状态的双向同步

运算符为系统内置组件提供 TS 变量的引用,实现 TS 变量和系统内置组件的内部状态保持同步。 ### 使用规则 $$ 运算符目前支持基础类型变量,以及被 @State、@Link 和 @Prop 装饰的变量。它目前仅支持 Refresh 组件的 refreshing 参数。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/1e6cf031035e42a2b6d8b17d8de229eb.png) ### 使用示例 以 Refresh 组件的 refreshing 参数为例,展示了 $$ 运算符的使用: ```typescript @Entry @Component struct RefreshExample { @State isRefreshing: boolean = false @State counter: number = 0 build() { Column() { Text('Pull Down and isRefreshing: ' + this.isRefreshing) .fontSize(30) .margin(10) Refresh({ refreshing: $$this.isRefreshing, offset: 120, friction: 100 }) { Text('Pull Down and refresh: ' + this.counter) .fontSize(30) .margin(10) } .onStateChange((refreshStatus: RefreshStatus) => { console.info('Refresh onStatueChange state is ' + refreshStatus) }) } } } ``` 在这个示例中,Refresh 组件的 refreshing 参数通过 $$ 运算符与 @State isRefreshing 变量进行绑定,保持了二者状态的双向同步。 # ArkTS 深度探索:@Watch 装饰器与 $$ 运算符的进阶应用 在前文中我们介绍了 ArkTS 中 @Watch 装饰器和 $$ 运算符的基本用法,现在让我们深入探讨它们的进阶应用场景和一些最佳实践。 ## 进阶应用:@Watch 与 @Link 组合 @Watch 装饰器和 @Link 装饰器的组合使用,为我们提供了在子组件中观察 @Link 变量的能力。以下是一个示例,演示了如何在子组件中观察 @Link 变量: ```typescript class PurchaseItem { static NextId: number = 0; public id: number; public price: number; constructor(price: number) { this.id = PurchaseItem.NextId++; this.price = price; } } @Component struct BasketViewer { @Link @Watch('onBasketUpdated') shopBasket: PurchaseItem[]; @State totalPurchase: number = 0; updateTotal(): number { let total = this.shopBasket.reduce((sum, item) => sum + item.price, 0); // 超过100欧元可享受折扣 if (total >= 100) { total = 0.9 * total; } return total; } // @Watch 回调 onBasketUpdated(propName: string): void { this.totalPurchase = this.updateTotal(); } build() { Column() { ForEach(this.shopBasket, (item) => { Text(`Price: ${item.price.toFixed(2)} €`); }, item => item.id.toString() ); Text(`Total: ${this.totalPurchase.toFixed(2)} €`); } } } @Entry @Component struct BasketModifier { @State shopBasket: PurchaseItem[] = []; build() { Column() { Button('Add to basket') .onClick(() => { this.shopBasket.push(new PurchaseItem(Math.round(100 * Math.random()))); }); BasketViewer({ shopBasket: $shopBasket }); } } } ``` 在这个例子中,BasketModifier 组件的按钮点击事件会将新的 PurchaseItem 添加到 shopBasket 数组中。@Link 装饰的 BasketViewer 组件的 shopBasket 值发生变化,状态管理框架调用 @Watch 函数 onBasketUpdated 更新了 BasketViewer 组件的 totalPurchase 值,触发了相应的重新渲染。 ## 最佳实践:@Watch 的异步操作 虽然 @Watch 被设计用于快速计算状态变量的改变,但有时候我们可能需要进行一些异步操作。然而,不建议在 @Watch 函数中直接使用 async/await,因为这可能导致重新渲染速度的性能问题。相反,我们可以采用其他方式来处理异步操作,例如使用 Promise。 ```typescript @Component struct ExampleComponent { @State data: string = ''; async fetchData() { // 模拟异步数据获取 const result = await fetchDataAsync(); return result; } // @Watch 回调 onFetchDataChanged(propName: string): void { this.fetchData().then(result => { // 处理异步数据 this.data = result; }); } build() { // UI 渲染逻辑 } } ``` 在这个例子中,onFetchDataChanged 回调函数中调用了异步 fetchData 方法,通过 Promise 处理异步操作,确保不会阻塞重新渲染的性能。 ## 总结 @Watch 装饰器和 $$ 运算符是 ArkTS 框架中强大的状态管理工具,通过它们的灵活运用,我们能够更好地处理组件状态的变化和同步。在实际应用中,我们建议开发者根据具体场景灵活选择使用,并结合最佳实践,以提高应用的性能和可维护性。 ArkTS 的状态管理机制为开发者提供了丰富的选择,使得构建复杂应用变得更加简便与高效。 ArkTS 的 @Watch 装饰器和 "$$" 运算符为开发者提供了更多灵活性和控制权。通过 @Watch,我们可以精确监听状态变量的变化,而 $ $ 运算符则让我们轻松实现内置组件状态与 TS 变量的双向同步。这些功能的合理使用将极大地提升 ArkTS 应用的可维护性和开发效率。在实际开发中,我们鼓励开发者 充分利用这些工具,发挥 ArkTS 框架的优势,构建更加强大和灵活的应用。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/f95b60b6c34049478d8d882ae05256f9.png)
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。