🧱 写在前面

很多 React 开发者初学 ArkTS 时,看到这样的代码会一脸困惑:

@Component
struct Greeting {
  build() {
    Text('Hello')
  }
}

“为什么是 struct?不是 function?这和我的 function App() {} 有什么关系?”

答案是:@Component + struct 就是 ArkTS 的“函数组件”,只是采用了更安全、更高效的声明方式。

本期我们将用 React 的思维,彻底搞懂鸿蒙的组件定义模型,打通从 JSX 到声明式 UI 的认知桥梁。


🔧 1. 为什么不用 function?因为 struct 更适合声明式 UI

React 函数组件(你熟悉的写法)

function Greeting({ name }: { name: string }) {
  return <p>Hello, {name}!</p>;
}

ArkTS 组件(鸿蒙的等价写法)

@Component
struct Greeting {
  name: string; // ← props 声明为 struct 成员

  build() {
    Text(`Hello, ${this.name}!`)
  }
}

✅ 为什么选择 struct 而非 function

维度 React 函数组件 ArkTS struct 组件
执行模型 每次渲染调用函数 编译为原生结构体,无函数调用开销
类型安全 依赖 TypeScript 接口 成员变量显式声明,编译时强校验
状态访问 依赖闭包(可能 stale) 直接访问 this.count,无闭包陷阱
内存效率 JS 引擎 GC 管理 ArkTS 运行时自动管理,更适合端侧设备

💡 核心思想一致:组件是 UI 的纯函数 —— 输入(props)→ 输出(UI)。
只是 ArkTS 选择了更适合高性能、低功耗场景的实现方式。


📦 2. Props 怎么传?成员变量就是你的 props!

在 React 中,props 是函数参数;在 ArkTS 中,props 是 struct 的成员变量

使用示例

// 定义组件
@Component
struct MyButton {
  label: string;        // 必填 props
  onClick?: () => void; // 可选 props(注意 ?)

  build() {
    Button(this.label)
      .onClick(() => this.onClick?.()) // 安全调用
  }
}

// 使用组件
MyButton({ 
  label: '提交', 
  onClick: () => console.log('clicked') 
})

🔑 关键规则

  • 所有 props 必须在 struct显式声明类型
  • 可选 props 用 ? 标记(如 onClick?: () => void
  • 调用时通过 { prop: value } 传递,语法与 React 几乎一致

✅ 这比 React 的 PropTypesinterface 更直接——类型即文档,编译即校验


🔄 3. 组件复用:组合优于继承(完全兼容 React 思维)

ArkTS 同样推崇“组合”而非“继承”。下面是一个用户卡片的组合示例:

// 子组件:头像
@Component
struct Avatar {
  src: Resource; // 鸿蒙资源类型
  size: number = 40; // 默认值

  build() {
    Image(this.src)
      .width(this.size)
      .height(this.size)
      .borderRadius(this.size / 2)
  }
}

// 子组件:用户名
@Component
struct UserName {
  name: string;
  isVIP: boolean = false;

  build() {
    Text(this.name)
      .fontSize(this.isVIP ? 18 : 16)
      .fontColor(this.isVIP ? '#e91e63' : '#333')
      .fontWeight(FontWeight.Bold)
  }
}

// 父组件:组合使用
@Component
struct UserCard {
  avatarSrc: Resource;
  userName: string;
  isVIP: boolean = false;

  build() {
    Row() {
      Avatar({ src: this.avatarSrc })
      UserName({ name: this.userName, isVIP: this.isVIP })
    }
    .alignItems(VerticalAlign.Center)
    .padding(10)
  }
}

💡 你会发现

  • 每个组件职责单一
  • 通过 Child({ ... }) 组合使用
  • 完全符合 React 的“组合哲学”

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

❌ 错误 1:未提供默认值,导致 props 必传

@Component
struct Title {
  text: string; // ← 无默认值,使用时必须传
  size: number; // ← 同样必须传,否则编译失败
}

✅ 正确做法:提供默认值,让 props 可选

size: number = 16; // ← 有默认值,可不传

❌ 错误 2:在 build() 外访问 this

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

  console.log(this.count); // ❌ 编译错误!不能在 build 外用 this

  build() {
    Button(`Count: ${this.count}`) // ✅ 正确
  }
}

✅ 正确:所有 UI 相关逻辑必须放在 build() 方法或事件回调中。


✅ 小结

  • @Component struct Xfunction X(props)
  • ✅ 成员变量 = props(显式声明,类型安全)
  • build() = return (JSX)(UI 构建入口)
  • ✅ 组件组合方式完全一致:Child({ prop: value })

你不是在学习面向对象,而是在用更安全、更高效的方式写函数式 UI。


🔜 下期预告

《useState 换个名字叫 @State,仅此而已》
我们将深入:

  • 如何声明组件状态?
  • 父子组件如何通信(@Prop vs @Link)?
  • 为什么直接赋值就能自动刷新 UI?

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


📚 参考资料

  • 学习UI范式基本语法

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


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


💬 互动提问:你觉得 structfunction 更难理解吗?你在定义组件时遇到过哪些编译错误?留言告诉我,我会在下期集中解答!

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐