[鸿蒙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 用于跨层级。

相关推荐
_阿南_11 小时前
项目中新增给AI制定的代码规范
前端·程序员
名字还没想好☜12 小时前
React 实现暗黑模式切换:localStorage 持久化、SSR 首屏闪烁与跟随系统主题
前端·javascript·react.js·ecmascript·react·next.js
console.log('npc')13 小时前
Git 冲突与 AI 协助指南
前端·人工智能·git·大模型
ChinaDragon13 小时前
HarmonyOS:6.0 新增和增强特性
harmonyos
爱学堂IT分享14 小时前
Cesium可视化系统实战课程-Cesium教程学习
前端
糖墨夕15 小时前
理解大语言模型:Agent 的“大脑”
前端·agent
Rain的Java大神之路15 小时前
JavaWeb开发如何解决跨域问题
java·前端·后端·nginx·web安全·面试·运维开发
cpolar技术支持15 小时前
浏览器也能跑本地 AI:用 Transformers.js + WebGPU 做一个最小推理 Demo,cpolar 给同事远程体验
前端·ai·cpolar·webgpu·transformers.js
贾伟康15 小时前
【句匠|01】HarmonyOS ArkTS 英语纠错页实战:把原句、修改建议和解释层级展示清楚
harmonyos·arkts·textarea·学习应用·英语纠错
计算机魔术师17 小时前
OpenAI 发布 GPT-6 Astra:多项基准刷新纪录, cybersecurity 能力达 Critical 阈值
前端