[鸿蒙2025领航者闯关] 鸿蒙应用中如何管理组件状态?

问题描述

鸿蒙应用中如何管理组件状态?@State、@Link、@Provide 有什么区别?如何实现父子组件、跨层级组件的数据传递?

关键字: @State、@Link、@Provide、@Consume、状态管理

解决方案

复制代码
/**
 * @State:组件内部状态
 */
@Component
struct StateDemo {
  @State count: number = 0;
  @State name: string = '张三';
  @State visible: boolean = false;
  
  build() {
    Column({ space: 12 }) {
      Text(`计数: ${this.count}`)
        .fontSize(18)
      
      Button('增加')
        .onClick(() => {
          this.count++; // 修改状态会触发UI更新
        })
      
      TextInput({ text: this.name })
        .onChange((value: string) => {
          this.name = value; // 双向绑定
        })
    }
    .padding(20)
  }
}
​
/**
 * @Link:父子双向绑定
 */
@Component
struct ChildComponent {
  @Link count: number; // 使用@Link接收
  
  build() {
    Column({ space: 8 }) {
      Text(`子组件显示: ${this.count}`)
      Button('子组件增加')
        .onClick(() => {
          this.count++; // 修改会同步到父组件
        })
    }
  }
}
​
@Component
struct ParentComponent {
  @State count: number = 0;
  
  build() {
    Column({ space: 12 }) {
      Text(`父组件显示: ${this.count}`)
      
      Button('父组件增加')
        .onClick(() => {
          this.count++;
        })
      
      // 使用$传递引用
      ChildComponent({ count: $count })
    }
    .padding(20)
  }
}
​
/**
 * @Provide/@Consume:跨层级传递
 */
@Entry
@Component
struct GrandParent {
  @Provide('theme') theme: string = 'light';
  @Provide('fontSize') fontSize: number = 16;
  
  build() {
    Column({ space: 16 }) {
      Text('祖父组件')
        .fontSize(20)
      
      Button('切换主题')
        .onClick(() => {
          this.theme = this.theme === 'light' ? 'dark' : 'light';
        })
      
      Parent()
    }
    .padding(20)
  }
}
​
@Component
struct Parent {
  build() {
    Column({ space: 12 }) {
      Text('父组件(不需要接收theme)')
      Child()
    }
  }
}
​
@Component
struct Child {
  @Consume('theme') theme: string; // 直接从祖父组件获取
  @Consume('fontSize') fontSize: number;
  
  build() {
    Column({ space: 8 }) {
      Text('子组件')
        .fontSize(this.fontSize)
      Text(`当前主题: ${this.theme}`)
        .fontColor(this.theme === 'light' ? '#333' : '#fff')
    }
  }
}
​
/**
 * @Watch:监听状态变化
 */
@Component
struct WatchDemo {
  @State @Watch('onCountChange') count: number = 0;
  @State @Watch('onNameChange') name: string = '';
  
  onCountChange() {
    console.log('count变化了:', this.count);
    if (this.count > 10) {
      promptAction.showToast({ message: '计数超过10了!' });
    }
  }
  
  onNameChange() {
    console.log('name变化了:', this.name);
  }
  
  build() {
    Column({ space: 12 }) {
      Text(`计数: ${this.count}`)
      Button('增加').onClick(() => this.count++)
      
      TextInput({ placeholder: '输入姓名' })
        .onChange((value: string) => {
          this.name = value;
        })
    }
    .padding(20)
  }
}
​
/**
 * @Prop:单向传递
 */
@Component
struct PropChild {
  @Prop count: number; // 只读,不能修改
  
  build() {
    Column() {
      Text(`接收到的值: ${this.count}`)
      // this.count++ // 错误!不能修改@Prop
    }
  }
}
​
@Component
struct PropParent {
  @State count: number = 0;
  
  build() {
    Column({ space: 12 }) {
      Button('父组件增加').onClick(() => this.count++)
      PropChild({ count: this.count }) // 直接传值
    }
  }
}
​
/**
 * @ObjectLink:对象双向绑定
 */
@Observed
class Person {
  name: string;
  age: number;
  
  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }
}
​
@Component
struct ObjectLinkChild {
  @ObjectLink person: Person;
  
  build() {
    Column({ space: 8 }) {
      Text(`姓名: ${this.person.name}`)
      Text(`年龄: ${this.person.age}`)
      Button('增加年龄')
        .onClick(() => {
          this.person.age++; // 修改会同步到父组件
        })
    }
  }
}
​
@Component
struct ObjectLinkParent {
  @State person: Person = new Person('张三', 25);
  
  build() {
    Column({ space: 12 }) {
      Text(`父组件: ${this.person.name}, ${this.person.age}岁`)
      ObjectLinkChild({ person: this.person })
    }
    .padding(20)
  }
}

关键要点

  1. @State: 组件内部状态,变化触发 UI 更新,用于基本类型和对象
  2. @Link : 父子组件双向绑定,使用 $count 传递引用,子组件修改会同步到父组件
  3. @Provide/@Consume: 跨层级传递,无需逐层传递,通过 key 匹配
  4. @Watch: 监听状态变化,执行副作用(如日志、提示等)
  5. @Prop: 单向传递,子组件只读,不能修改
  6. @ObjectLink: 对象双向绑定,需要配合 @Observed 使用

避坑指南

  1. **忘记 符号** : @Link 必须用 `count` 传递,否则报错
  2. Provide 名称: @Provide 和 @Consume 的 key 必须完全一致
  3. 性能: 避免过多 @State,每个 @State 变化都会触发重绘
  4. 对象修改: @State 对象属性修改不会触发更新,需要整体赋值或用 @ObjectLink
  5. Watch 循环: @Watch 回调中修改被监听的状态会导致无限循环

总结

掌握 @State/@Link/@Provide 是鸿蒙开发的基础,合理使用可以简化状态管理,提高代码可维护性。@State 用于组件内部,@Link 用于父子,@Provide 用于跨层级。

相关推荐
一只大侠的侠4 小时前
Flutter开源鸿蒙跨平台训练营 Day 10特惠推荐数据的获取与渲染
flutter·开源·harmonyos
崔庆才丨静觅6 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60617 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了7 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅7 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅8 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅8 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment8 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅8 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊8 小时前
jwt介绍
前端