首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

鸿蒙HarmonyOS开发框架—学习ArkTS语言(状态管理 二)

  • 25-02-22 03:20
  • 2907
  • 7470
blog.csdn.net

@Prop装饰器:父子单向同步

@Prop装饰的变量可以和父组件建立单向的同步关系。@Prop装饰的变量是可变的,但是变化不会同步回其父组件。

概述

@Prop装饰的变量和父组件建立单向的同步关系:

  • @Prop变量允许在本地修改,但修改后的变化不会同步回父组件。
  • 当父组件中的数据源更改时,与之相关的@Prop装饰的变量都会自动更新。如果子组件已经在本地修改了@Prop装饰的相关变量值,而在父组件中对应的@State装饰的变量被修改后,子组件本地修改的@Prop装饰的相关变量值将被覆盖。
装饰器使用规则说明

@Prop变量装饰器

说明

装饰器参数

无

同步类型

单向同步:对父组件状态变量值的修改,将同步给子组件@Prop装饰的变量,子组件@Prop变量的修改不会同步到父组件的状态变量上

允许装饰的变量类型

string、number、boolean、enum类型。 不支持any,不允许使用undefined和null。 必须指定类型。 在父组件中,传递给@Prop装饰的值不能为undefined或者null,反例如下所示。 CompA ({ aProp: undefined }) CompA ({ aProp: null }) @Prop和数据源类型需要相同,有以下三种情况(数据源以@State为例): @Prop装饰的变量和父组件状态变量类型相同,即@Prop : S和@State : S当父组件的状态变量为数组时,@Prop装饰的变量和父组件状态变量的数组项类型相同,即@Prop : S和@State : Array当父组件状态变量为Object或者class时,@Prop装饰的变量和父组件状态变量的属性类型相同,即@Prop : S和@State : { propA: S }

被装饰变量的初始值

允许本地初始化。

  • @Prop装饰的变量和父组件状态变量类型相同,即@Prop : S和@State : S
  • 当父组件的状态变量为数组时,@Prop装饰的变量和父组件状态变量的数组项类型相同,即@Prop : S和@State : Array
  • 当父组件状态变量为Object或者class时,@Prop装饰的变量和父组件状态变量的属性类型相同,即@Prop : S和@State : { propA: S }

被装饰变量的初始值 允许本地初始化。

变量的传递/访问规则说明

传递/访问

说明

从父组件初始化

如果本地有初始化,则是可选的。没有的话,则必选,支持父组件中的常规变量、@State、@Link、@Prop、@Provide、@Consume、@ObjectLink、@StorageLink、@StorageProp、@LocalStorageLink和@LocalStorageProp去初始化子组件中的@Prop变量。

用于初始化子组件

@Prop支持去初始化子组件中的常规变量、@State、@Link、@Prop、@Provide。

是否支持组件外访问

@Prop装饰的变量是私有的,只能在组件内访问。

图1 初始化规则图示

观察变化和行为表现
观察变化

@Prop装饰的数据可以观察到以下变化。

  • 当装饰的类型是允许的类型,即string、number、boolean、enum类型都可以观察到的赋值变化;
  1. // 简单类型
  2. @Prop count: number;
  3. // 赋值的变化可以被观察到
  4. this.count = 1;

复制

对于@State和@Prop的同步场景:

  • 使用父组件中@State变量的值初始化子组件中的@Prop变量。当@State变量变化时,该变量值也会同步更新至@Prop变量。
  • @Prop装饰的变量的修改不会影响其数据源@State装饰变量的值。
  • 除了@State,数据源也可以用@Link或@Prop装饰,对@Prop的同步机制是相同的。
  • 数据源和@Prop变量的类型需要相同。
框架行为

要理解@Prop变量值初始化和更新机制,有必要了解父组件和拥有@Prop变量的子组件初始渲染和更新流程。

  1. 初始渲染:
    1. 执行父组件的build()函数将创建子组件的新实例,将数据源传递给子组件;
    2. 初始化子组件@Prop装饰的变量。
  2. 更新:
    1. 子组件@Prop更新时,更新仅停留在当前子组件,不会同步回父组件;
    2. 当父组件的数据源更新时,子组件的@Prop装饰的变量将被来自父组件的数据源重置,所有@Prop装饰的本地的修改将被父组件的更新覆盖。
使用场景
父组件@State到子组件@Prop简单数据类型同步

以下示例是@State到子组件@Prop简单数据同步,父组件ParentComponent的状态变量countDownStartValue初始化子组件CountDownComponent中@Prop装饰的count,点击“Try again”,count的修改仅保留在CountDownComponent 不会同步给父组件CountDownComponent。

ParentComponent的状态变量countDownStartValue的变化将重置CountDownComponent的count。

  1. @Component
  2. struct CountDownComponent {
  3. @Prop count: number;
  4. costOfOneAttempt: number = 1;
  5. build() {
  6. Column() {
  7. if (this.count > 0) {
  8. Text(`You have ${this.count} Nuggets left`)
  9. } else {
  10. Text('Game over!')
  11. }
  12. // @Prop装饰的变量不会同步给父组件
  13. Button(`Try again`).onClick(() => {
  14. this.count -= this.costOfOneAttempt;
  15. })
  16. }
  17. }
  18. }
  19. @Entry
  20. @Component
  21. struct ParentComponent {
  22. @State countDownStartValue: number = 10;
  23. build() {
  24. Column() {
  25. Text(`Grant ${this.countDownStartValue} nuggets to play.`)
  26. // 父组件的数据源的修改会同步给子组件
  27. Button(`+1 - Nuggets in New Game`).onClick(() => {
  28. this.countDownStartValue += 1;
  29. })
  30. // 父组件的修改会同步给子组件
  31. Button(`-1 - Nuggets in New Game`).onClick(() => {
  32. this.countDownStartValue -= 1;
  33. })
  34. CountDownComponent({ count: this.countDownStartValue, costOfOneAttempt: 2 })
  35. }
  36. }
  37. }

在上面的示例中:

  1. CountDownComponent子组件首次创建时其@Prop装饰的count变量将从父组件@State装饰的countDownStartValue变量初始化;
  2. 按“+1”或“-1”按钮时,父组件的@State装饰的countDownStartValue值会变化,这将触发父组件重新渲染,在父组件重新渲染过程中会刷新使用countDownStartValue状态变量的UI组件并单向同步更新CountDownComponent子组件中的count值;
  3. 更新count状态变量值也会触发CountDownComponent的重新渲染,在重新渲染过程中,评估使用count状态变量的if语句条件(this.count > 0),并执行true分支中的使用count状态变量的UI组件相关描述来更新Text组件的UI显示;
  4. 当按下子组件CountDownComponent的“Try again”按钮时,其@Prop变量count将被更改,但是count值的更改不会影响父组件的countDownStartValue值;
  5. 父组件的countDownStartValue值会变化时,父组件的修改将覆盖掉子组件CountDownComponent中count本地的修改。
父组件@State数组项到子组件@Prop简单数据类型同步

父组件中@State如果装饰的数组,其数组项也可以初始化@Prop。以下示例中父组件Index中@State装饰的数组arr,将其数组项初始化子组件Child中@Prop装饰的value。

  1. @Component
  2. struct Child {
  3. @Prop value: number;
  4. build() {
  5. Text(`${this.value}`)
  6. .fontSize(50)
  7. .onClick(()=>{this.value++})
  8. }
  9. }
  10. @Entry
  11. @Component
  12. struct Index {
  13. @State arr: number[] = [1,2,3];
  14. build() {
  15. Row() {
  16. Column() {
  17. Child({value: this.arr[0]})
  18. Child({value: this.arr[1]})
  19. Child({value: this.arr[2]})
  20. Divider().height(5)
  21. ForEach(this.arr,
  22. item => {
  23. Child({value: item})
  24. },
  25. item => item.toString()
  26. )
  27. Text('replace entire arr')
  28. .fontSize(50)
  29. .onClick(()=>{
  30. // 两个数组都包含项“3”。
  31. this.arr = this.arr[0] == 1 ? [3,4,5] : [1,2,3];
  32. })
  33. }
  34. }
  35. }
  36. }

复制

初始渲染创建6个子组件实例,每个@Prop装饰的变量初始化都在本地拷贝了一份数组项。子组件onclick事件处理程序会更改局部变量值。

假设我们点击了多次,所有变量的本地取值都是“7”。

  1. 7
  2. 7
  3. 7
  4. ----
  5. 7
  6. 7
  7. 7

复制

单击replace entire arr后,屏幕将显示以下信息,为什么?

  1. 3
  2. 4
  3. 5
  4. ----
  5. 7
  6. 4
  7. 5

复制

  • 在子组件Child中做的所有的修改都不会同步回父组件Index组件,所以即使6个组件显示都为7,但在父组件Index中,this.arr保存的值依旧是[1,2,3]。
  • 点击replace entire arr,this.arr[0] == 1成立,将this.arr赋值为[3, 4, 5];
  • 因为this.arr[0]已更改,Child({value: this.arr[0]})组件将this.arr[0]更新同步到实例@Prop装饰的变量。Child({value: this.arr[1]})和Child({value: this.arr[2]})的情况也类似。
  • this.arr的更改触发ForEach更新,this.arr更新的前后都有数值为3的数组项:[3, 4, 5] 和[1, 2, 3]。根据diff机制,数组项“3”将被保留,删除“1”和“2”的数组项,添加为“4”和“5”的数组项。这就意味着,数组项“3”的组件不会重新生成,而是将其移动到第一位。所以“3”对应的组件不会更新,此时“3”对应的组件数值为“7”,ForEach最终的渲染结果是“7”,“4”,“5”。
从父组件中的@State类对象属性到@Prop简单类型的同步

如果图书馆有一本图书和两位用户,每位用户都可以将图书标记为已读,此标记行为不会影响其它读者用户。从代码角度讲,对@Prop图书对象的本地更改不会同步给图书馆组件中的@State图书对象。

  1. class Book {
  2. public title: string;
  3. public pages: number;
  4. public readIt: boolean = false;
  5. constructor(title: string, pages: number) {
  6. this.title = title;
  7. this.pages = pages;
  8. }
  9. }
  10. @Component
  11. struct ReaderComp {
  12. @Prop title: string;
  13. @Prop readIt: boolean;
  14. build() {
  15. Row() {
  16. Text(this.title)
  17. Text(`... ${this.readIt ? 'I have read' : 'I have not read it'}`)
  18. .onClick(() => this.readIt = true)
  19. }
  20. }
  21. }
  22. @Entry
  23. @Component
  24. struct Library {
  25. @State book: Book = new Book('100 secrets of C++', 765);
  26. build() {
  27. Column() {
  28. ReaderComp({ title: this.book.title, readIt: this.book.readIt })
  29. ReaderComp({ title: this.book.title, readIt: this.book.readIt })
  30. }
  31. }
  32. }

复制

@Prop本地初始化不和父组件同步

为了支持@Component装饰的组件复用场景,@Prop支持本地初始化,这样可以让@Prop是否与父组件建立同步关系变得可选。当且仅当@Prop有本地初始化时,从父组件向子组件传递@Prop的数据源才是可选的。

下面的示例中,子组件包含两个@Prop变量:

  • @Prop customCounter没有本地初始化,所以需要父组件提供数据源去初始化@Prop,并当父组件的数据源变化时,@Prop也将被更新;
  • @Prop customCounter2有本地初始化,在这种情况下,@Prop依旧允许但非强制父组件同步数据源给@Prop。
  1. @Component
  2. struct MyComponent {
  3. @Prop customCounter: number;
  4. @Prop customCounter2: number = 5;
  5. build() {
  6. Column() {
  7. Row() {
  8. Text(`From Main: ${this.customCounter}`).width(90).height(40).fontColor('#FF0010')
  9. }
  10. Row() {
  11. Button('Click to change locally !').width(480).height(60).margin({ top: 10 })
  12. .onClick(() => {
  13. this.customCounter2++
  14. })
  15. }.height(100).width(480)
  16. Row() {
  17. Text(`Custom Local: ${this.customCounter2}`).width(90).height(40).fontColor('#FF0010')
  18. }
  19. }
  20. }
  21. }
  22. @Entry
  23. @Component
  24. struct MainProgram {
  25. @State mainCounter: number = 10;
  26. build() {
  27. Column() {
  28. Row() {
  29. Column() {
  30. Button('Click to change number').width(480).height(60).margin({ top: 10, bottom: 10 })
  31. .onClick(() => {
  32. this.mainCounter++
  33. })
  34. }
  35. }
  36. Row() {
  37. Column()
  38. // customCounter必须从父组件初始化,因为MyComponent的customCounter成员变量缺少本地初始化;此处,customCounter2可以不做初始化。
  39. MyComponent({ customCounter: this.mainCounter })
  40. // customCounter2也可以从父组件初始化,父组件初始化的值会覆盖子组件customCounter2的本地初始化的值
  41. MyComponent({ customCounter: this.mainCounter, customCounter2: this.mainCounter })
  42. }.width('40%')
  43. }
  44. }
  45. }

最后,为了能让大家更好的去学习提升鸿蒙 (Harmony OS) 开发技术,小编连夜整理了一份30个G纯血版学习资料(含视频、电子书、学习文档等)以及一份在Github上持续爆火霸榜的《纯血版华为鸿蒙 (Harmony OS)开发手册》(共计890页),希望对大家有所帮助。

纯血版鸿蒙 HarmonyOS 4.0 视频学习资料

 需要以上视频学习资料小伙伴

请点击→纯血版全套鸿蒙HarmonyOS学习资料


《纯血版华为鸿蒙 (Harmony OS)开发手册》

这份手册涵盖了当前鸿蒙 (Harmony OS) 开发技术必掌握的核心知识点

纯血版鸿蒙 (Harmony OS)开发手册部分精彩内容

HarmonyOS 概念:

  • 系统定义
  • 技术架构
  • 技术特性
  • 系统安全

如何快速入门?

  • 基本概念
  • 构建第一个ArkTS应用
  • 构建第一个JS应用
  • ……


开发基础知识: 

  • 应用基础知识
  • 配置文件
  • 应用数据管理
  • 应用安全管理
  • 应用隐私保护
  • 三方应用调用管控机制
  • 资源分类与访问
  • 学习ArkTS语言
  • ……

基于ArkTS 开发:

  • Ability开发
  • UI开发
  • 公共事件与通知
  • 窗口管理
  • 媒体
  • 安全
  • 网络与链接
  • 电话服务
  • 数据管理
  • 后台任务(Background Task)管理
  • 设备管理
  • 设备使用信息统计
  • DFX
  • 国际化开发
  • 折叠屏系列
  • .……

获取以上文中提到的这份纯血版鸿蒙 (Harmony OS) 开发资料的小伙伴 

请点击→纯血版全套鸿蒙HarmonyOS学习资料


?写在最后

  • 如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙:
  • 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
  • 关注小编,同时可以期待后续文章ing?,不定期分享原创知识。
  • 想要获取更多完整鸿蒙最新VIP学习资料,请点击→纯血版全套鸿蒙HarmonyOS学习资料

最新鸿蒙Next全套学习资料请扫码
微信名片
注:本文转载自blog.csdn.net的蜀道山QAQ的文章"https://blog.csdn.net/shudaoshanQAQ/article/details/135612283"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

101
推荐
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top