🔄 写在前面

上一期我们成功跑通了第一个 HarmonyOS 页面,很多 React 开发者留言问:

“那状态怎么管理?有 useState 吗?”

答案是:有,而且更简单——它叫 @State

本期我们将深入 HarmonyOS 的状态系统,用你最熟悉的 React 思维,掌握 @State@Prop@Link 三大装饰器,并实现一个可交互的“消息编辑器”。

你会发现:鸿蒙的状态管理,不过是 React props 和 state 的另一种表达。


🔁 1. 组件内状态:@State = useState

React 写法

const Counter = () => {
  const [count, setCount] = useState(0);
  return (
    <button onClick={() => setCount(c => c + 1)}>
      Count: {count}
    </button>
  );
};

ArkTS 写法

@Component
struct Counter {
  @State count: number = 0; // ← 响应式状态声明

  build() {
    Button(`Count: ${this.count}`)
      .onClick(() => {
        this.count += 1; // ← 直接赋值,自动触发 UI 更新
      })
  }
}

✅ 核心机制对比

特性 React ArkTS
状态声明 const [val, setVal] = useState() @State val: Type = init
状态更新 调用 setVal(newValue) 直接赋值 this.val = newValue
更新触发 虚拟 DOM diff 声明式 UI 引擎自动重绘
是否需记忆化 有时需要 useCallback 不需要

💡 关键理解:在 ArkTS 中,状态即 UI 的源头。只要 @State 变量变化,依赖它的 UI 自动刷新——无需手动调用更新函数。


📦 2. 父子通信:@Prop 与 @Link(props 的两种形态)

React 中,props 是只读的。但在鸿蒙中,根据是否需要双向同步,分为两类:

▶ 场景一:父 → 子(只读)→ @Prop

// 父组件
@Entry
@Component
struct Parent {
  @State message: string = 'Hello from Parent';

  build() {
    Child({ msg: this.message }) // 传递值副本
  }
}

// 子组件
@Component
struct Child {
  @Prop msg: string; // ← 只读,不能修改

  build() {
    Text(this.msg)
  }
}

⚠️ 若在子组件中写 this.msg = 'new'编译时报错@Prop is readonly.


▶ 场景二:父 ↔ 子(双向)→ @Link

// 父组件:注意 $ 符号!
build() {
  Child({ msg: $message }) // ← $ 表示“传递引用”
}

// 子组件
@Component
struct Child {
  @Link msg: string; // ← 双向绑定

  build() {
    TextInput({ text: this.msg })
      .onChange((value) => {
        this.msg = value; // ← 修改会同步回父组件!
      })
  }
}

🔑 $message 是 ArkTS 特有语法,表示“创建对 message 的引用”,类似 Vue 的 .sync 或 SolidJS 的响应式信号。


⚠️ 3. 新手常见错误(避坑指南)

❌ 错误 1:用普通变量代替响应式状态

build() {
  let temp = 'hello'; // ❌ 非响应式,UI 不会更新
}

✅ 正确:所有驱动 UI 的数据必须用 @State / @Prop / @Link 声明。


❌ 错误 2:未初始化 @State

@State count: number; // ❌ 编译错误:必须初始化!

✅ 正确:

@State count: number = 0;
// 或
@State count?: number; // 可选类型,但使用时需判空

❌ 错误 3:在 @Prop 上赋值

@Prop title: string;
// ...
this.title = 'updated'; // ❌ 运行时错误或编译失败

✅ 正确:只读属性不要修改;如需双向,请改用 @Link


🛠️ 4. 实战:实现一个“消息编辑器”

结合所学,构建一个父子组件联动的编辑器:

// 主页面
@Entry
@Component
struct MessageEditor {
  @State message: string = 'Hello, HarmonyOS!';

  build() {
    Column() {
      // 显示区域(只读)
      Text(this.message)
        .fontSize(20)
        .padding(10)
        .backgroundColor($r('sys.color.glass_material_outline_secondary'))

      // 编辑区域(双向绑定)
      MessageInput({ msg: $message })
    }
    .width('100%')
    .padding(20)
  }
}

// 输入组件
@Component
struct MessageInput {
  @Link msg: string;

  build() {
    TextInput({
      text: this.msg,
      placeholder: 'Edit message...'
    })
      .onChange((value) => {
        this.msg = value;
      })
  }
}

效果

  • 在输入框中打字 → 上方文本实时同步
  • 完美实现父子状态联动!

在这里插入图片描述


✅ 小结

  • @State = 组件内状态(≈ useState
  • @Prop = 只读 props(≈ React props)
  • @Link = 双向绑定 props(通过 $ 传递引用)
  • 直接赋值即可触发 UI 更新,无需 setter 函数

你不是在学习新范式,而是在用新语法表达已有的 React 思维。


📚 参考资料


系列名称:《React 开发者的鸿蒙入门指南


🔜 下期预告

《列表渲染不用 map,用 ForEach!》
我们将深入:

  • 如何高效渲染长列表?
  • ForEach 的 key 函数怎么写?
  • 为什么鸿蒙的 Listreact-window 更省性能?

关注我,持续解锁 React → 鸿蒙实战技能!

欢迎点赞、收藏、评论交流!你的支持是我持续输出的动力!
点击主页关注,获取更多前端 × 鸿蒙实战内容!


💬 互动提问:你在使用 @State 时遇到过哪些奇怪问题?留言告诉我,点赞最高的问题,下期优先解答!

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐