• HarmonyOS学习路之方舟开发框架—学习ArkTS语言(状态管理 八)


    其他状态管理概述

    除了前面章节提到的组件状态管理和应用状态管理,ArkTS还提供了@Watch和$$来为开发者提供更多功能:

    • @Watch用于监听状态变量的变化。
    • $$运算符:给内置组件提供TS变量的引用,使得TS变量和内置组件的内部状态保持同步。

    @Watch装饰器:状态变量更改通知

    @Watch应用于对状态变量的监听。如果开发者需要关注某个状态变量的值是否改变,可以使用@Watch为状态变量设置回调函数。

    概述

    @Watch用于监听状态变量的变化,当状态变量变化时,@Watch的回调方法将被调用。@Watch在ArkUI框架内部判断数值有无更新使用的是严格相等(===),遵循严格相等规范。当在严格相等为false的情况下,就会触发@Watch的回调。

    装饰器说明

    @Watch补充变量装饰器

    说明

    装饰器参数

    必填。常量字符串,字符串需要有引号。是(string) => void自定义成员函数的方法的引用。

    可装饰的自定义组件变量

    可监听所有装饰器装饰的状态变量。不允许监听常规变量。

    装饰器的顺序

    建议@State、@Prop、@Link等装饰器在@Watch装饰器之前。

    语法说明

    类型

    说明

    (changedPropertyName? : string) => void

    该函数是自定义组件的成员函数,changedPropertyName是被watch的属性名。

    在多个状态变量绑定同一个@Watch的回调方法的时候,可以通过changedPropertyName进行不同的逻辑处理

    将属性名作为字符串输入参数,不返回任何内容。

    观察变化和行为表现

    1. 当观察到状态变量的变化(包括双向绑定的AppStorage和LocalStorage中对应的key发生的变化)的时候,对应的@Watch的回调方法将被触发;
    2. @Watch方法在自定义组件的属性变更之后同步执行;
    3. 如果在@Watch的方法里改变了其他的状态变量,也会引起的状态变更和@Watch的执行;
    4. 在第一次初始化的时候,@Watch装饰的方法不会被调用,即认为初始化不是状态变量的改变。只有在后续状态改变时,才会调用@Watch回调方法。

    限制条件

    • 建议开发者避免无限循环。循环可能是因为在@Watch的回调方法里直接或者间接地修改了同一个状态变量引起的。为了避免循环的产生,建议不要在@Watch的回调方法里修改当前装饰的状态变量;
    • 开发者应关注性能,属性值更新函数会延迟组件的重新渲染(具体请见上面的行为表现),因此,回调函数应仅执行快速运算;
    • 不建议在@Watch函数中调用async await,因为@Watch设计的用途是为了快速的计算,异步行为可能会导致重新渲染速度的性能问题。

    使用场景

    @Watch和自定义组件更新

    以下示例展示组件更新和@Watch的处理步骤。count在CountModifier中由@State装饰,在TotalView中由@Prop装饰。

    1. @Component
    2. struct TotalView {
    3. @Prop @Watch('onCountUpdated') count: number;
    4. @State total: number = 0;
    5. // @Watch cb
    6. onCountUpdated(propName: string): void {
    7. this.total += this.count;
    8. }
    9. build() {
    10. Text(`Total: ${this.total}`)
    11. }
    12. }
    13. @Entry
    14. @Component
    15. struct CountModifier {
    16. @State count: number = 0;
    17. build() {
    18. Column() {
    19. Button('add to basket')
    20. .onClick(() => {
    21. this.count++
    22. })
    23. TotalView({ count: this.count })
    24. }
    25. }
    26. }

    处理步骤:

    1. CountModifier自定义组件的Button.onClick点击事件自增count。
    2. 由于@State count变量更改,子组件TotalView中的@Prop被更新,其@Watch('onCountUpdated')方法被调用,更新了子组件TotalView 中的total变量。
    3. 子组件TotalView中的Text重新渲染。

    @Watch与@Link组合使用

    以下示例说明了如何在子组件中观察@Link变量。

    1. class PurchaseItem {
    2. static NextId: number = 0;
    3. public id: number;
    4. public price: number;
    5. constructor(price: number) {
    6. this.id = PurchaseItem.NextId++;
    7. this.price = price;
    8. }
    9. }
    10. @Component
    11. struct BasketViewer {
    12. @Link @Watch('onBasketUpdated') shopBasket: PurchaseItem[];
    13. @State totalPurchase: number = 0;
    14. updateTotal(): number {
    15. let total = this.shopBasket.reduce((sum, i) => sum + i.price, 0);
    16. // 超过100欧元可享受折扣
    17. if (total >= 100) {
    18. total = 0.9 * total;
    19. }
    20. return total;
    21. }
    22. // @Watch 回调
    23. onBasketUpdated(propName: string): void {
    24. this.totalPurchase = this.updateTotal();
    25. }
    26. build() {
    27. Column() {
    28. ForEach(this.shopBasket,
    29. (item) => {
    30. Text(`Price: ${item.price.toFixed(2)} €`)
    31. },
    32. item => item.id.toString()
    33. )
    34. Text(`Total: ${this.totalPurchase.toFixed(2)} €`)
    35. }
    36. }
    37. }
    38. @Entry
    39. @Component
    40. struct BasketModifier {
    41. @State shopBasket: PurchaseItem[] = [];
    42. build() {
    43. Column() {
    44. Button('Add to basket')
    45. .onClick(() => {
    46. this.shopBasket.push(new PurchaseItem(Math.round(100 * Math.random())))
    47. })
    48. BasketViewer({ shopBasket: $shopBasket })
    49. }
    50. }
    51. }

    处理步骤如下:

    1. BasketModifier组件的Button.onClick向BasketModifier shopBasket中添加条目;
    2. @Link装饰的BasketViewer shopBasket值发生变化;
    3. 状态管理框架调用@Watch函数BasketViewer onBasketUpdated 更新BasketViewer TotalPurchase的值;
    4. @Link shopBasket的改变,新增了数组项,ForEach组件会执行item Builder,渲染构建新的Item项;@State totalPurchase改变,对应的Text组件也重新渲染;重新渲染是异步发生的。

    $$语法:内置组件双向同步

    $$运算符为系统内置组件提供TS变量的引用,使得TS变量和系统内置组件的内部状态保持同步。

    内部状态具体指什么取决于组件。例如,bindPopup属性方法的show参数。

    使用规则

    • 当前$$支持基础类型变量,以及@State、@Link和@Prop装饰的变量。
    • 当前$$仅支持bindPopup属性方法的show参数,Radio
      组件的checked属性,Refresh
      组件的refreshing参数。
    • $$绑定的变量变化时,会触发UI的同步刷新。

    使用示例

    以bindPopup属性方法的show参数为例:

    1. // xxx.ets
    2. @Entry
    3. @Component
    4. struct bindPopupPage {
    5. @State customPopup: boolean = false;
    6. build() {
    7. Column() {
    8. Button('Popup')
    9. .margin(20)
    10. .onClick(() => {
    11. this.customPopup = !this.customPopup
    12. })
    13. .bindPopup($$this.customPopup, {
    14. message: 'showPopup'
    15. })
    16. }
    17. }
    18. }

  • 相关阅读:
    HarmonyOS/OpenHarmony原生应用-ArkTS万能卡片组件Toggle
    Codeforces Round #818 (Div. 2)
    C++——如何正确的使用STL中list?
    当resource bundle 的多语言文件里包含引号'时
    NeRF神经辐射场渲染过程详解,三维重建渲染过程基本原理_光线采样sample_pdf()和光线渲染render_rays ()代码详解
    Nvidia GPU 入门教程之 01 Ubuntu如何开启SSH,查看存储情况,查看A100 GPU显卡情况
    C语言中,字节对齐是一种重要的内存管理概念
    electron开发桌面程序mac/window,配合vue3+vite进行配置开发
    第8章 函数探幽
    笔试强训第24天--(年终奖 + 迷宫问题)
  • 原文地址:https://blog.csdn.net/weixin_47094733/article/details/133633203