来源华为开发者官网 - @State装饰器:组件内状态
本笔记全面、系统地整理了该页面所有内容,包含详细说明、表格归纳、代码示例与核心知识点解析,便于深入学习和复习使用。

一、概述

    @State 是 ArkTS 中用于声明 组件内部状态变量 的装饰器。被 @State 修饰的变量具有响应式特性:当其值发生变化时,会自动触发 UI 重新渲染,从而实现动态交互效果。

  • 属于 本地状态管理

  • 仅可在自定义组件中使用

  • 支持基本类型和引用类型

  • 需要初始化赋值

  • 修改后自动驱动 UI 更新

二、核心特性概览表

特性 说明
装饰器名称 @State
作用目标 自定义组件内的成员变量
是否必需初始化 是,必须在声明时赋予初始值
支持的数据类型 基本类型(numberstringboolean)、对象、数组等
响应式机制 变量重新赋值可触发 UI 刷新;不支持对对象/数组内部的原地修改监听
作用域 组件内部私有状态,不可跨组件共享
生命周期 与组件实例绑定,随组件创建而初始化,销毁而释放
更新条件 必须通过赋值操作符(=)改变整个变量的值才能触发 UI 更新
与其他装饰器关系 可与 @Prop@Link@Provide@Consume 配合使用,但用途不同

三、语法格式

@State <variableName>: <Type> = <initialValue>;

示例:

@State count: number = 0;
@State title: string = "默认标题";
@State isActive: boolean = true;
@State userInfo: object = { name: "Tom", age: 18 };
@State list: Array<string> = ["A", "B", "C"];

四、完整代码示例

示例 1:基础计数器(数字类型)

@Component
struct CounterExample {
  @State count: number = 0;

  build() {
    Column({ space: 20 }) {
      Text(`当前计数:${this.count}`)
        .fontSize(24)
        .fontWeight(FontWeight.Bold)

      Button("增加")
        .onClick(() => {
          this.count += 1; // 触发 UI 更新
        })

      Button("减少")
        .onClick(() => {
          this.count -= 1; // 触发 UI 更新
        })
    }
    .width('100%')
    .padding(20)
  }
}

示例 2:布尔值控制显示隐藏

@Component
struct VisibilityExample {
  @State isVisible: boolean = true;

  build() {
    Column({ space: 20 }) {
      if (this.isVisible) {
        Text("这段文字可以被切换显示")
          .fontSize(20)
          .backgroundColor(Color.Blue)
          .padding(10)
          .textColor(Color.White)
      }

      Button(this.isVisible ? "隐藏" : "显示")
        .onClick(() => {
          this.isVisible = !this.isVisible; // 切换状态并刷新 UI
        })
    }
    .width('100%')
    .padding(20)
  }
}

示例 3:对象更新(需替换整个对象)

⚠️ 注意:直接修改属性不会触发 UI 更新!

@Component
struct ObjectUpdateExample {
  @State person: { name: string; age: number } = { name: "Alice", age: 30 };

  build() {
    Column({ space: 20 }) {
      Text(`姓名:${this.person.name}`)
        .fontSize(20)
      Text(`年龄:${this.person.age}`)
        .fontSize(20)

      Button("修改姓名")
        .onClick(() => {
          // ❌ 错误方式:不会触发 UI 更新
          // this.person.name = "Bob";

          // ✅ 正确方式:深拷贝或结构赋值后重新赋值
          this.person = { ...this.person, name: "Bob" };
        })

      Button("增加年龄")
        .onClick(() => {
          this.person = { ...this.person, age: this.person.age + 1 };
        })
    }
    .width('100%')
    .padding(20)
  }
}

示例 4:数组更新(不可变操作)

⚠️ 直接索引修改或 push 不会触发更新!

@Component
struct ArrayUpdateExample {
  @State items: string[] = ['Apple', 'Banana'];

  build() {
    Column({ space: 20 }) {
      ForEach(this.items, (item: string) => {
        Text(item)
          .fontSize(18)
          .padding(5)
          .borderRadius(4)
          .backgroundColor('#f0f0f0')
      }, item => item)

      Button("添加元素")
        .onClick(() => {
          // ✅ 使用 concat 返回新数组
          this.items = this.items.concat(`Item ${this.items.length + 1}`);
        })

      Button("删除第一个")
        .onClick(() => {
          // ✅ 使用 slice 创建新数组
          this.items = this.items.slice(1);
        })

      Button("使用 map 修改全部")
        .onClick(() => {
          this.items = this.items.map(item => `${item}-updated`);
        })
    }
    .width('100%')
    .padding(20)
  }
}

五、常见错误及正确做法对比表

操作类型 错误写法 是否触发 UI 更新 正确写法 是否触发 UI 更新
数字加减 this.count++ 或 this.count += 1 同上
字符串拼接 this.msg += 'new' 使用模板字符串再赋值
修改对象属性 this.user.name = "New" this.user = { ...this.user, name: "New" }
修改数组元素 this.list[0] = "X" this.list = [...this.list]; this.list[0]="X";
数组 push this.list.push("new") this.list = this.list.concat("new")
删除数组项 this.list.splice(0,1) this.list = this.list.slice(1)

💡 小贴士:所有需要触发 UI 更新的操作都应遵循“不可变数据”原则 —— 返回一个新对象/新数组,并整体赋值给 @State 变量。

六、限制与注意事项

注意事项 详细说明
不能用于静态变量 @State static count: number = 0; ❌ 不允许
不能用于局部变量 不能在函数内部使用 @State let x = 1; ❌
必须初始化 @State count: number; ❌ 编译报错
不能为 undefined/null 初始化值不能为 undefined 或 null(除非类型允许)
不监听深层变化 对象嵌套层级过深时,需手动触发顶层对象替换
避免循环引用 定义复杂对象时注意不要造成内存泄漏或无限递归

七、与其他状态装饰器对比表

装饰器 数据流向 使用场景 是否响应式 所属组件
@State 内部状态 管理组件自身状态 当前组件
@Prop 父→子(单向) 接收父组件传递的只读属性 ✅(父变更触发子更新) 子组件
@Link 双向绑定 子组件同步修改父组件状态 子组件
@Provide / @Consume 多层传递(祖先→后代) 跨多级组件通信 任意层级
@ObjectLink 链接到 @State 对象 在子组件中展示复杂对象 ✅(配合 @Observed 子组件

八、最佳实践建议

实践 推荐方式
命名规范 使用有意义的名称,如 isLoadinguserNameitemList
单一职责 每个 @State 变量尽量只负责一个逻辑状态
拆分复杂状态 若对象过于复杂,考虑拆分为多个 @State 或结合 @Observed
使用不可变操作 始终采用 mapfiltersliceconcat, 扩展运算符等方式生成新数据
性能优化 避免频繁无意义的状态变更,防止过度重绘

九、总结

    @State 是构建动态 UI 的基石,它使得开发者可以通过简单的变量赋值来驱动界面更新。然而,必须理解其 响应式机制基于“赋值检测”而非“属性修改监听”,因此:

✅ 正确姿势是:永远用“新对象”或“新数组”替换旧值
❌ 错误姿势是:直接修改对象属性或数组元素而不重新赋值

掌握这一点是高效使用 ArkTS 进行 HarmonyOS 应用开发的关键前提。

知识点详解

  • 响应式系统原理:框架通过元数据拦截 @State 变量的 set 操作,触发 UI 重建。

  • 不可变数据模式:推荐使用函数式方法生成新数据,确保状态可追踪且可预测。

  • UI 自动刷新机制:每次 @State 变量被赋新值,都会调用组件的 build() 方法更新视图。

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新

更多推荐