当前位置: 首页 > article >正文

鸿蒙Harmony–状态管理器–@State详解

鸿蒙Harmony–状态管理器–@State详解

1.1 定义

@State装饰的变量,或者称为状态变量,一旦变量拥有了状态属性,就可以触发其直接绑定UI组件的刷新。当状态改变时,UI会发生对应的渲染变化 ,@State装饰的变量,与声明式范式中的其他被装饰变量一样,是私有的,只能从组件内部访问。在声明时候必须本地初始化

1.1.1 案例演示

  1. 代码示意
import { promptAction } from '@kit.ArkUI'

@Entry
@Component
struct Test {

  num: number = 1

  build() {
    Column() {
      Row({space:20}) {
        Button('+')
          .onClick(()=>{
            this.num++
            promptAction.showToast({
              message:this.num+''
            })
          })
        Text(this.num + '')
        Button('-')
          .onClick(()=>{
            this.num--
            promptAction.showToast({
              message:this.num+''
            })
          })
      }
    }.width('100%')
    .height('100%')
  }
}
  1. 演示

如下图显示,点击Button按钮,UI界面并不会更新,但是我们通过弹层提示是可以明显看到数据变化了的,

img

  1. 加上@State装饰器后的正确效果
import { promptAction } from '@kit.ArkUI'

@Entry
@Component
struct Test {
 @State
  num: number = 1

  build() {
    Column() {
      Row({space:20}) {
        Button('+')
          .onClick(()=>{
            this.num++
            promptAction.showToast({
              message:this.num+''
            })
          })
        Text(this.num + '')
        Button('-')
          .onClick(()=>{
            this.num--
            promptAction.showToast({
              message:this.num+''
            })
          })
      }
    }.width('100%')
    .height('100%')
  }
}

img

通过上述案例,我们可以得出结论,@State装饰器修饰的数据变化可以让UI发生变化,但是在鸿蒙中,@State装饰器也有限制。在修饰引用数据的时候,@State装饰器只能监测对象自身和第一层的变化

1.2@State装饰器的限制以及解决办法

1.2.1限制

@State修饰引用类型的数据时候,只能在自身或者第一层发生变化的时候产生更新

  1. 案例
import { promptAction } from '@kit.ArkUI';

@Entry
@Component
struct Test01 {
  //1.数据驱动UI变化  加上@State装饰器
  @State
  persionInfo: PersionInfo = {
    name: '小程',
    age: '21',
    sex: '女',
    address: {
      province: '安徽',
      city: '黄山市',
      area: '黄山'
    }
  }

  build() {
    Column() {
      Row() {
        Text('姓名:')
        TextInput({ text: this.persionInfo.name })
          .layoutWeight(1)
      }.width('100%')
      .padding(20)

      Row() {
        Text('年龄:')
        TextInput({ text: this.persionInfo.age })
          .layoutWeight(1)
      }.width('100%')
      .padding(20)

      Row() {
        Text('性别:')
        TextInput({ text: this.persionInfo.sex })
          .layoutWeight(1)
      }.width('100%')
      .padding(20)

      Row({ space: 10 }) {
        Text('地址:')
        TextInput({ text: this.persionInfo.address.province })
          .layoutWeight(1)
        TextInput({ text: this.persionInfo.address.city })
          .layoutWeight(1)
        TextInput({ text: this.persionInfo.address.area })
          .layoutWeight(1)
      }.width('100%')
      .padding(20)

      Row({ space: 20 }) {
        Button('改变姓名')
          .onClick(() => {
            this.persionInfo.name = '小程神'
          })
        Button('改变省份')
          .onClick(() => {
            this.persionInfo.address.province = '河北'
            promptAction.showToast({
              message: JSON.stringify(this.persionInfo.address)
            })
          })
      }
    }.width('100%')
    .height('100%')
  }
}

interface Address {
  province: string
  city: string
  area: string
}

interface PersionInfo {
  name: string
  age: string
  sex: '男' | '女'
  address: Address
}
  1. 效果展示

img

  1. 案例分析
  • 在我们修改姓名的时候,姓名也是成功修改,但是我们在修改省份的时候,却没有成功修改,但是数据其实更改的了,但是UI层并没有更新,这就涉及到了鸿蒙里面@State装饰器修饰的引用数据只能修改本身或者第一层数据,而省份是在address里面的第二层,所以自然不会刷新,所以通过修改自身和第一层我们可以更新省份

1.2.2解决方法

  1. 方法一:修改第一层
  • 代码
 Button('改变省份')
          .onClick(() => {
            this.persionInfo.address = {
              province:'河北',
              city:'保定',
              area:'莲池区'
            }
            promptAction.showToast({
              message: JSON.stringify(this.persionInfo.address)
            })
          })
  • 效果展示

img

2.方法二:修改自身

  • 代码演示
     Button('改变省份')
          .onClick(() => {
            // this.persionInfo.address = {
            //   province:'河北',
            //   city:'保定',
            //   area:'莲池区'
            // }
            this.persionInfo={
              name: '小程',
              age: '21',
              sex: '女',
              address: {
                province: '河北',
                city: '黄山市',
                area: '黄山'
              }

            }
            promptAction.showToast({
              message: JSON.stringify(this.persionInfo.address)
            })
          })
  • 效果展示

img

通过上述方法,我们可以总结为UI更新的原理就是产生了一个新对象,得到一个新对象,UI就会更新,另辟蹊径,我们可以把接口转换为类,然后new一个对象去赋值,然后更新UI

  1. 方法三:new 一个新对象
  • 代码展示
export class AddressModel implements Address {
  province: string = ''
  city: string = ''
  area: string = ''

  constructor(model: Address) {
    this.province = model.province
    this.city = model.city
    this.area = model.area
  }
}
export class PersionInfoModel implements PersionInfo {
  name: string = ''
  age: string = ''
  sex: '男' | '女' = '男'
  address: Address = new AddressModel({} as Address)

  constructor(model: PersionInfo) {
    this.name = model.name
    this.age = model.age
    this.sex = model.sex
    this.address = model.address
  }
}
    Button('改变省份')
          .onClick(() => {
            // this.persionInfo.address = {
            //   province:'河北',
            //   city:'保定',
            //   area:'莲池区'
            // }
            // this.persionInfo={
            //   name: '小程',
            //   age: '21',
            //   sex: '女',
            //   address: {
            //     province: '河北',
            //     city: '黄山市',
            //     area: '黄山'
            //   }
            //
            // }
            this.persionInfo.address.province = '四川'
            this.persionInfo = new PersionInfoModel(this.persionInfo)
            promptAction.showToast({
              message: JSON.stringify(this.persionInfo.address)
            })
  • 效果展示

img

1.3总结

  1. @State装饰器可以通过数据驱动视图更新
  2. 在鸿蒙中,@State只能监听到引用数据的本身和第一层,不能监听到第二层
  3. 如果想监听到第二层以及第二层往后,可以改变数据的本身、第一层或者new一个新对象

http://www.kler.cn/a/532019.html

相关文章:

  • Java 大视界 -- Java 大数据在智能医疗影像诊断中的应用(72)
  • 趣味Python100例初学者练习01
  • 模拟实战-用CompletableFuture优化远程RPC调用
  • 如何在电脑上部署deepseek
  • 单调队列 滑动窗口(题目分析+C++完整代码)
  • 数据 类型
  • Vue 3 30天精进之旅:Day 14 - 项目实践
  • 【图片识别分类】批量按图片水印文字识别后根据内容分类并移至不同文件夹,基于Python和腾讯API的解决方案
  • 雷赛LC2000
  • 『 C++ 』中不可重写虚函数的实用案例
  • JVM监控和管理工具
  • 与本地Deepseek R1:14b的第一次交流
  • Dest1ny攻防实战:SpringBoot 脱敏属性***明文获取
  • FORTRAN语言的云计算
  • 蓝桥杯例题七
  • RocketMQ面试题:进阶部分
  • 给AI用工具的能力——Agent
  • Redis基础(二)——通用命令与五大基本数据类型
  • 排序算法--基数排序
  • Alibaba开发规范_MySQL索引规约:最佳实践与常见陷阱
  • 一篇关于高等数理统计结合机器学习论文的撰写(如何撰写?)
  • 响应式编程_01基本概念:前世今生
  • 防火墙安全策略实验
  • [vue.draggable.next]-Vue3中后台管理系统实现拖拽排序功能
  • Python面向对象编程:用对象思维构建数字世界
  • Linux:文件系统(软硬链接)