11-ArkTS语言_状态管理

状态管理

  • @State:@State装饰的变量拥有其所属组件的状态,可以作为其子组件单向和双向同步的数据源。当其数值改变时,会引起相关组件的渲染刷新,初始化必须赋值。
  • @Prop:@Prop装饰的变量可以和父组件建立单向同步关系,@Prop装饰的变量是可变的,但修改不会同步回父组件,即不会改变父组件的内容,初始化不可以赋值。
  • @Link:@Link装饰的变量和父组件构建双向同步关系的状态变量,父组件会接受来自@Link装饰的变量的修改的同步,父组件的更新也会同步给@Link装饰的变量,初始化不可以赋值。
  • @Provide/@Consume:@Provide/@Consume装饰的变量用于跨组件层级(多层组件)同步状态变量,可以不需要通过参数命名机制传递,通过alias(别名)或者属性名绑定。
  • @Observed:@Observed装饰class,需要观察多层嵌套场景的class需要被@Observed装饰。单独使用@Observed没有任何作用,需要和@ObjectLink、@Prop连用。
  • @ObjectLink:@ObjectLink装饰的变量接收@Observed装饰的class的实例,应用于观察多层嵌套场景,和父组件的数据源构建双向同步。

@State----->@Prop 和 @State <-----> @Link

  • 驱动build()更新
  • @State —> @Prop (this.进行传参)
  • @State <–> @Link(传参使用$)

在这里插入图片描述

@Entry
@Component
  // 父页面
struct Statemanagement {
  message: string = '@State装饰'
  @State stateMessage: string = '父组件数据'

  build() {
    Column() {
      Column() {
        Text(this.message)
          .titleExtend()
        Text(this.stateMessage)
          .showExtend()
        Button('改变State数据')
          .btnExtend(() => {
            this.stateMessage = this.stateMessage === '父页面数据' ? '父页面数据改变' : '父页面数据'
          })
        //   this.stateMessage = this.stateMessage == '父页面数据' ? '父页面数据改变' : '父页面数据'
        // })
      }
      .columnSty()

      stateManagment_prop({ propMessage: this.stateMessage })
      // stateManagment_Link({linkMessage:this.stateMessage})
      // 如果是state < --- > link 参数传递时,使用$变量名进行传递
      stateManagment_Link({ linkMessage: $stateMessage })
    }
    .width('100%')
    .height('100%')
  }
}
// 存放一个 @Prop 装饰的状态数据。方便父子组件之间进行数据传递和同步  State ----> prop
@Component
struct stateManagment_prop {
  message: string = '@Prop装饰'
  @Prop propMessage: string

  build() {
    Column() {
      Text(this.message).titleExtend()
      Text('@Prop:' + this.propMessage).showExtend()
      Button('改变Prop组件数据')
        .btnExtend(() => {
          this.propMessage = '@Prop'
        })
    }
    .columnSty()
  }
}

// 用来存放@Link数据
@Component
struct stateManagment_Link {
  message: string = '@Link装饰'
  @Link linkMessage: string

  build() {
    Column() {
      Text(this.message).titleExtend()
      Text('@Link:' + this.linkMessage).showExtend()
      Button('改变Link组件数据')
        .btnExtend(() => {
          this.linkMessage = '@Link'
        })
    }
    .columnSty()
  }
}
// Text 标题文字样式
@Extend(Text) function titleExtend() {
  .width('90%')
  .fontSize(20)
  .fontWeight(FontWeight.Bold)
}

// Text 展示文字样式
@Extend(Text) function showExtend() {
  .fontSize(20)
  .fontWeight(FontWeight.Bolder)
}

// column样式
@Extend(Column) function columnSty() {
  .margin({
    top:'3vp'
  })
  .width('95%')
  .height('30%')
  .borderStyle(BorderStyle.Solid)
  .borderColor(Color.Black)
  .border({ width: 1 })
  .justifyContent(FlexAlign.SpaceAround)
}

// button样式
@Extend(Button) function btnExtend(click: Function) {
  .fontSize(30)
  .height('40vp')
  .onClick(() => {
    click()
  })
}

@Provide装饰器和@Consume装饰器:与后代组件双向同步

@Provide和@Consume,应用于与后代组件的双向数据同步,应用于状态数据在多个层级之间传递的场景。不同于上文提到的父子组件之间通过命名参数机制传递,@Provide和@Consume摆脱参数传递机制的束缚,实现跨层级传递。
其中@Provide装饰的变量是在祖先节点中,可以理解为被“提供”给后代的状态变量。@Consume装饰的变量是在后代组件中,去“消费(绑定)”祖先节点提供的变量。
@Provide/@Consume装饰的状态变量有以下特性:

  • @Provide装饰的状态变量自动对其所有后代组件可用,即该变量被“provide”给他的后代组件。由此可见,@Provide的方便之处在于,开发者不需要多次在组件之间传递变量。
  • 后代通过使用@Consume去获取@Provide提供的变量,建立在@Provide和@Consume之间的双向数据同步,与@State/@Link不同的是,前者可以在多层级的父子组件之间传递。
  • @Provide和@Consume可以通过相同的变量名或者相同的变量别名绑定,变量类型必须相同。
// 相同的变量名
@Provide wechat:string = '学习鸿蒙'
@Consume wechat: string

// 相同的变量别名
@Provide('shy') wechat:string = '学习鸿蒙'
@Consume('shy') wechat_son: string

@Provide和@Consume通过相同的变量名或者相同的变量别名绑定时,@Provide修饰的变量和@Consume修饰的变量是一对多的关系。不允许在同一个自定义组件内,包括其子组件中声明多个同名或者同别名的@Provide装饰的变量。


@Entry
  @Component
  struct ProvideConsume {
    @Provide('theshy') wechat: string = '微信公众号'

    build() {
      Row() {
        Column({ space: 20 }) {
          Text(this.wechat).ProvideConsume_textStyle()
            .onClick(() => {
              this.wechat = '不多讲故事'
            })
          Divider()
          // 父调用子。
          ProvideConsume_son()
        }.width('100%')
      }.height('100%')
    }
  }

@Component
  struct ProvideConsume_son {
    build() {
      Column({ space: 20 }) {
        Text('子组件的布局内容:').ProvideConsume_textStyle()
        Divider()
        // 调用孙组件
        ProvideConsume_sun()
      }
    }
  }

@Component
  struct ProvideConsume_sun {
    @Consume('theshy') study: string

    build() {
      Column() {
        Text('孙:' + this.study).ProvideConsume_textStyle()
          .onClick(() => {
            this.study = 'HarmonyOS4.0'
          })
      }
    }
  }

@Extend(Text) function ProvideConsume_textStyle() {
  .fontSize(30)
    .fontWeight(700)
}

@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 修饰  状态数据
 *  函数中,不要不要不要修改被监视的状态变量。 我们要操作的是其他的业务逻辑
 * */
@Entry
  @Component
  struct WatchDct {
    @State @Watch('change') count: number = 1
    @State @Watch('change') pow: number = 2
    @State res: number = 1

    change() {
      // this.count = this.count + 2  无限循环
      this.res = Math.pow(this.count, this.pow)
    }

    build() {
      Row() {
        Column() {
          Text('基数:' + this.count)
            .fontSize(50)
            .onClick(() => {
              this.count++
            })

          Divider()
          Text(`次幂:${this.pow}`)
            .fontSize(50)
            .onClick(() => {
              this.pow++
            })

          Divider()
          Text("结果:" + this.res)
            .fontSize(50)
        }
        .width('100%')
      }
      .height('100%')
    }
  }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值