HarmonyOS NEXT鸿蒙开发 ArkUI:@Prop 和 @State 区别 作者:马育民 • 2025-10-14 10:21 • 阅读:10005 # 介绍 在 ArkTS 中,`@Prop` 和 `@State` 都是用于管理组件状态的装饰器,但它们的**作用域**和**数据流向**有本质区别,核心差异体现在“状态的归属”和“跨组件数据传递能力”上。 ### 一句话解释 - `@State` 是“自己的状态自己管” - `@Prop` 是“父传子的状态子使用” 两者结合实现了组件内部状态管理与父子组件单向数据传递的核心能力。 ### 适用场景 - **`@State`**:组件需要管理自身的动态状态(如按钮点击次数、表单输入值、弹窗显示状态等),且状态无需传递给其他组件。 - **`@Prop`**:子组件需要根据父组件的参数动态渲染(如不同文本内容、不同样式配置),且子组件无需修改父组件的数据,仅需“被动接收”并展示。 # 区别 | 特性 | `@State` | `@Prop` | |------|----------|---------| | **状态归属** | 组件**内部私有状态**,由当前组件创建和管理 | 组件**从父组件接收的状态**,归属权在父组件 | | **数据流向** | 仅在当前组件内部生效,修改后触发自身 UI 更新 | 父组件 → 子组件的**单向数据流**(父变子更,子变不影响父) | | **初始化方式** | 必须在当前组件内初始化(如 `@State count: number = 0`) | 不能在子组件内初始化,必须由父组件传递值(除非设置默认值) | | **作用场景** | 管理组件自身的动态状态(如按钮点击次数、弹窗开关) | 接收父组件传递的数据,实现子组件的个性化渲染 | ### 1. 状态的归属与管理 ##### `@State`:组件自己的状态 `@State` 修饰的变量是组件**内部创建和管理**的状态,完全由当前组件控制。例如: ```typescript @Component struct Counter { // 组件自己的计数器状态,初始值由组件自身定义 @State count: number = 0; build() { Button(`点击次数:${this.count}`) .onClick(() => this.count++); // 组件自己修改状态 } } ``` ##### `@Prop`:父组件传递的状态 `@Prop` 修饰的变量是组件**从父组件“借来”的状态**,其值由父组件提供,子组件仅负责使用(不推荐修改,即使修改也不会影响父组件)。例如: ```typescript // 子组件:接收父组件的状态 @Component struct ShowMessage { // 状态由父组件传递,子组件不能自己初始化 @Prop message: string; build() { Text(this.message); // 仅使用父组件传递的值 } } // 父组件:提供状态并传递给子组件 @Component struct Parent { @State parentMsg: string = "Hello"; build() { Column() { ShowMessage({ message: this.parentMsg }); // 传递状态 } } } ``` ### 2. 数据流向与同步规则 ##### `@State`:仅内部同步 `@State` 变量的变化**只会影响当前组件**的 UI,不会传递给其他组件。例如: ```typescript @Component struct InnerStateDemo { @State isShow: boolean = false; build() { Column() { Button("切换显示") .onClick(() => this.isShow = !this.isShow); // 修改内部状态 if (this.isShow) { Text("我是内部状态控制的文本"); // 仅当前组件受影响 } } } } ``` ##### `@Prop`:单向同步(父传子) 父组件传递给子组件的 `@Prop` 变量,会在**父组件数据变化时自动同步到子组件**,但子组件修改 `@Prop` 变量**不会反向影响父组件**。例如: ```typescript // 子组件 @Component struct Child { @Prop count: number; build() { Column() { Text(`子组件接收的值:${this.count}`) // 子组件修改@Prop,不会影响父组件 Button("子组件增加") .onClick(() => this.count++); } } } // 父组件 @Component struct Parent { @State parentCount: number = 0; build() { Column() { Text(`父组件原始值:${this.parentCount}`) Button("父组件增加") .onClick(() => this.parentCount++); // 父组件修改,子组件会同步 Child({ count: this.parentCount }) // 传递状态 } } } ``` 上述代码中: - 父组件点击“父组件增加”,`parentCount` 变化 → 子组件 `count` 自动同步更新。 - 子组件点击“子组件增加”,`count` 变化 → 父组件 `parentCount` 不变(单向性)。 ### 3. 初始化要求 ##### `@State`:必须在组件内初始化 `@State` 是组件自己的状态,声明时必须赋值(否则编译报错): ```typescript @State name: string = "默认名称"; // 正确:有初始值 @State age: number; // 错误:未初始化 ``` ##### `@Prop`:禁止在子组件内初始化,由父组件传递 `@Prop` 是父组件传递的状态,子组件不能自己初始化,但可以设置默认值(父组件未传递时使用): ```typescript @Prop message: string; // 正确:由父组件传递 @Prop count: number = 0; // 正确:设置默认值(父组件可省略传递) @Prop title: string = "标题"; // 父组件未传递时,使用"标题" ``` 原文出处:http://www.malaoshi.top/show_1GW22SJb0lho.html