一文搞清楚HarmonyOS NEXT中状态管理 V1 版本:父子组件数据传递装饰器的奇妙之旅

简介: 本文深入浅出地介绍了HarmonyOS NEXT开发中状态管理V1版本的两个核心装饰器:@Prop和@Link。@Prop如同单向传递的快递员,负责将数据从父组件传递到子组件,但子组件的修改不会影响父组件;@Link则像心灵感应的双胞胎,实现父组件与子组件间的数据双向同步。通过魔法按钮和能量水晶的生动示例,文章详细解析了两者的使用场景、参数特性及同步机制,并以浅拷贝和深拷贝为比喻,帮助开发者更好地理解数据传递中的细节。掌握这两位“信使”,能让组件间的协作更加高效可靠!

程序员Feri一名12年+的程序员,做过开发带过团队创过业,擅长Java、嵌入式、鸿蒙、人工智能等,专注于程序员成长那点儿事,希望在成长的路上有你相伴!君志所向,一往无前!





状态管理 V1 版本:父子组件数据传递装饰器的奇妙之旅


在HarmonyOS NEXT开发的奇妙世界里,组件就像是一个个独立的小王国,它们各自有着自己的职责和功能。但是,这些小王国之间并不是孤立存在的,它们需要相互交流、相互协作,才能构建出一个完整而强大的应用帝国。


而在这个过程中,数据传递就像是王国之间的信使,负责在不同的组件之间传递信息。


在状态管理的 V1 版本中,我们有两位强大的信使:@Prop@Link。它们各自有着独特的能力,能够帮助我们实现父子组件之间的数据传递。接下来,让我们一起踏上这场奇妙的旅程,探索它们的奥秘吧!


1. @Prop:单向传递的快递员


1.1 基本概念


想象一下,有一个快递员叫 @Prop,他负责从一个王国(父组件)向另一个王国(子组件)传递包裹(数据)。


这个快递员有一个特殊的规则:他只负责把包裹从父组件送到子组件,而子组件对包裹所做的任何修改,他都不会带回给父组件。


1.2 装饰器参数


@Prop 就像是一个不需要任何证件的快递员,他不需要任何参数就能工作。


1.3 同步类型


单向同步。这就好比父组件是包裹的发送者,子组件是包裹的接收者。


发送者可以随时发送新的包裹,接收者会收到最新的包裹内容。但是,接收者对包裹所做的任何修改,发送者都不会知道。


1.4 允许装饰的变量类型


@Prop 这个快递员非常能干,几乎什么类型的包裹都能送。


他可以送 Objectclassstringnumberbooleanenum 类型的包裹,甚至还可以送这些类型的数组包裹。


1.5 被装饰变量的初始值


@Prop 允许子组件在收到包裹之前,先给自己准备一个初始的包裹内容。但是,一旦收到父组件的包裹,这个初始内容就会被父组件的包裹内容覆盖。


1.6 示例代码


下面是一个有趣的示例,展示了 @Prop 的使用:


doubaocanvas


// 子组件:魔法按钮
@Component
export struct MagicButton {
  // 魔法按钮的图标库
  magicIcons: Resource[] = [
    $r("sys.media.star"),
    $r("sys.media.moon"),
    $r("sys.media.sun")
  ];
  
  // 按钮的当前状态
  @State currentState: number = 0;
  
  // 按钮的名称,由父组件传递
  @Prop buttonName: string = "普通按钮";

  build() {
    Column() {
      // 显示当前的魔法图标
      Image(this.magicIcons[this.currentState])
        .width(100)
        .height(100)
        .animation({ duration: 500, curve: "ease-in-out" });
      
      // 魔法按钮
      Button(this.buttonName)
        .onClick(() => {
          // 切换魔法状态
          this.currentState = (this.currentState + 1) % 3;
          
          // 尝试修改按钮名称,但这不会影响父组件
          this.buttonName = 魔法状态<span class="hljs-subst">${<span class="hljs-keyword">this</span>.currentState}</span>;
          console.log(子组件将按钮名称改为:<span class="hljs-subst">${<span class="hljs-keyword">this</span>.buttonName}</span>);
        })
        .width(150)
        .height(50)
        .backgroundColor("#6200EA")
        .fontColor(Color.White)
        .borderRadius(25);
    }
    .width("100%")
    .height("100%")
    .justifyContent(FlexAlign.Center);
  }
}

// 父组件:魔法控制中心
@Entry
@Component
struct MagicControlCenter {
  // 控制中心的状态
  @State magicWord: string = "魔法";
  
  build() {
    Column() {
      // 输入魔法词
      TextInput({ placeholder: "输入魔法词..." })
        .onChange(v => {
          this.magicWord = v;
          console.log(父组件设置魔法词为:<span class="hljs-subst">${<span class="hljs-keyword">this</span>.magicWord}</span>);
        })
        .width("80%")
        .margin({ top: 50 })
        .backgroundColor("#E0E0E0")
        .borderRadius(10)
        .padding(10);
      
      // 显示当前魔法词
      Text(当前魔法词:<span class="hljs-subst">${<span class="hljs-keyword">this</span>.magicWord}</span>)
        .fontSize(18)
        .margin({ top: 20 });
      
      // 使用魔法按钮
      MagicButton({ buttonName: this.magicWord })
        .margin({ top: 50 });
    }
    .width("100%")
    .height("100%")
    .padding(20);
  }
}

1.7 代码解释


在这个魔法世界的示例中,我们有一个魔法控制中心(父组件)和一个魔法按钮(子组件)。控制中心可以通过输入框设置魔法词,然后将这个魔法词作为 buttonName 属性传递给魔法按钮。


当我们在控制中心输入新的魔法词时,魔法按钮会立即更新显示新的名称。但是,当我们点击魔法按钮时,虽然按钮内部会尝试修改 buttonName,但这个修改不会影响到控制中心的 magicWord。这就好比魔法按钮只是在自己的小世界里改变了按钮名称的副本,而真正的魔法词仍然掌握在控制中心手中。


2. @Link:心灵感应的双胞胎


2.1 基本概念


现在,让我们认识另一位神奇的信使 @Link。他就像是一对心灵感应的双胞胎,无论相隔多远,其中一个的想法和感受都会立即被另一个感知到。


在组件的世界里,@Link 可以让父组件和子组件共享同一个数据,任何一方对数据的修改都会立即反映到另一方。


2.2 装饰器参数


@Link 就像一对不需要任何介绍的双胞胎,他们之间的心灵感应是天生的,不需要任何参数来建立联系。


2.3 同步类型


双向同步。这意味着父组件和子组件就像双胞胎一样,任何一方对共享数据的修改都会立即被另一方感知到。


2.4 允许装饰的变量类型


@Link 这对双胞胎非常包容,几乎可以共享任何类型的数据。


他们可以共享 Objectclassstringnumberbooleanenum 类型的数据,甚至还可以共享这些类型的数组和 Date 类型的数据。


2.5 被装饰变量的初始值


@Link 这对双胞胎必须从同一个源头获得他们的初始数据,因此子组件不能自己初始化 @Link 装饰的变量,必须由父组件提供初始值。


2.6 示例代码


下面是一个有趣的示例,展示了 @Link 的使用:


doubaocanvas


// 子组件:能量水晶
@Component
export struct EnergyCrystal {
  // 水晶的不同形态
  crystalForms: Resource[] = [
    $r("sys.media.crystal_blue"),
    $r("sys.media.crystal_green"),
    $r("sys.media.crystal_purple")
  ];
  
  // 水晶的当前状态
  @State currentForm: number = 0;
  
  // 能量值,与父组件双向绑定
  @Link energyLevel: number;
  
  // 上次点击时间,用于防止双击
  @State lastClickTime: number = 0;

  build() {
    Column() {
      // 显示当前水晶形态
      Image(this.crystalForms[this.currentForm])
        .width(150)
        .height(150)
        .animation({ duration: 500, curve: "spring" });
      
      // 显示当前能量值
      Text(能量值:<span class="hljs-subst">${<span class="hljs-keyword">this</span>.energyLevel}</span>)
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
        .margin({ top: 20 })
        .fontColor(this.getEnergyColor());
      
      // 点击水晶增加能量
      Button("点击水晶增加能量")
      .onClick(() => {
        const now = Date.now();
        // 防止双击
        if (now - this.lastClickTime > 300) {
          this.lastClickTime = now;
          
          // 增加能量值
          this.energyLevel += 10;
          
          // 根据能量值改变水晶形态
          this.currentForm = Math.floor(this.energyLevel / 100) % 3;
          
          // 播放能量增加动画
          this.playEnergyAnimation();
        }
      });
    }
    .width("100%")
    .height("100%")
    .justifyContent(FlexAlign.Center);
  }
  
  // 根据能量值获取颜色
  getEnergyColor() {
    if (this.energyLevel < 50return Color.Red;
    if (this.energyLevel < 100return Color.Orange;
    return Color.Green;
  }
  
  // 播放能量增加动画
  playEnergyAnimation() {
    // 这里可以添加更复杂的动画效果
    console.log("能量增加动画播放");
  }
}

// 父组件:能量监控站
@Entry
@Component
struct EnergyMonitoringStation {
  // 总能量值
  @State totalEnergy: number = 0;
  
  // 能量收集器数量
  @State collectorCount: number = 1;
  
  build() {
    Column() {
      // 显示总能量
      Text(总能量:<span class="hljs-subst">${<span class="hljs-keyword">this</span>.totalEnergy}</span>)
        .fontSize(24)
        .fontWeight(FontWeight.Bold)
        .margin({ top: 30 });
      
      // 能量收集器控制
      Row() {
        Text("能量收集器数量:")
          .fontSize(18);
        
        Button("-")
          .onClick(() => {
            if (this.collectorCount > 1) {
              this.collectorCount--;
            }
          })
          .width(40)
          .height(40)
          .backgroundColor("#B71C1C")
          .fontColor(Color.White)
          .margin({ left: 20 });
        
        Text(<span class="hljs-subst">${<span class="hljs-keyword">this</span>.collectorCount}</span>)
          .fontSize(18)
          .margin({ left: 10, right: 10 });
        
        Button("+")
          .onClick(() => {
            if (this.collectorCount < 3) {
              this.collectorCount++;
            }
          })
          .width(40)
          .height(40)
          .backgroundColor("#2E7D32")
          .fontColor(Color.White);
      }
      .margin({ top: 20 });
      
      // 显示能量收集器
      ForEach(Array(this.collectorCount).fill(0), (_, index) => {
        EnergyCrystal({ energyLevel: this.totalEnergy })
          .margin({ top: 30 });
      });
      
      // 全局能量控制
      Button("重置能量")
        .onClick(() => {
          this.totalEnergy = 0;
        })
        .width("80%")
        .height(50)
        .backgroundColor("#1A237E")
        .fontColor(Color.White)
        .margin({ top: 50 })
        .borderRadius(25);
    }
    .width("100%")
    .height("100%")
    .padding(20);
  }
}


2.7 代码解释


在这个能量世界的示例中,我们有一个能量监控站(父组件)和一个或多个能量水晶(子组件)。


监控站负责监控总能量值,而能量水晶则负责收集能量。


当我们点击能量水晶时,水晶的能量值会增加。由于能量值是通过 @Link 与父组件双向绑定的,所以父组件的总能量值也会立即增加。


同样地,当我们在父组件中重置能量值时,所有子组件的能量值也会立即更新。


这就好比能量监控站和能量水晶是一对心灵感应的双胞胎,无论哪一方的能量发生变化,另一方都能立即感知到并做出相应的反应。


3. 浅拷贝和深拷贝的奇妙比喻


在我们的数据传递旅程中,还有两个重要的概念需要理解:浅拷贝和深拷贝。


让我们用一个有趣的比喻来解释它们。


假设你有一本非常珍贵的魔法书,里面有许多强大的咒语。浅拷贝就像是给这本书拍了一张照片,照片上的咒语看起来和原书一模一样,但实际上只是一个图像,如果你试图在照片上修改咒语,是不会有任何效果的。


而深拷贝则像是完全复制了一本魔法书,包括书中的每一个字、每一个魔法符号。这两本书是完全独立的,你可以在其中一本上随意修改咒语,而不会影响另一本。


@Prop@Link 的使用中,如果传递的是引用类型的数据(如对象或数组),就需要注意是使用浅拷贝还是深拷贝,以避免意外的数据修改。


4. 总结


在这场奇妙的旅程中,我们认识了两位强大的信使:@Prop@Link@Prop 就像是一个单向传递的快递员,负责将数据从父组件传递到子组件,但不会将子组件的修改带回给父组件。


@Link 则像是一对心灵感应的双胞胎,让父组件和子组件能够共享数据,任何一方的修改都会立即被另一方感知到。


通过这两位信使,我们可以在组件之间建立起高效、可靠的数据传递通道,让我们的应用帝国更加稳固和强大。


希望通过这个生动有趣的比喻,你对 @Prop@Link 有了更深入的理解。在你的HarmonyOS NEXT开发旅程中,好好利用这两位信使,创造出更加精彩的应用吧!



好啦,本篇就到这里啦,加油哟!关注我,跟我一起成长哈!



相关文章
|
2月前
|
移动开发 前端开发 JavaScript
鸿蒙NEXT时代你所不知道的全平台跨端框架:CMP、Kuikly、Lynx、uni-app x等
本篇基于当前各大活跃的跨端框架的现状,对比当前它们的情况和未来的可能,帮助你在选择框架时更好理解它们的特点和差异。
272 0
|
1月前
|
移动开发 网络协议 小程序
鸿蒙NEXT即时通讯/IM系统RinbowTalk v2.4版发布,基于MobileIMSDK框架、ArkTS编写
RainbowTalk是一套基于开源即时通讯讯IM框架 MobileIMSDK 的产品级鸿蒙NEXT端IM系统。纯ArkTS编写、全新开发,没有套壳、也没走捷径,每一行代码都够“纯血”。与姊妹产品RainbowChat和RainbowChat-Web 技术同源,历经考验。
68 1
|
2月前
|
缓存 移动开发 网络协议
纯血鸿蒙NEXT即时通讯/IM系统:RinbowTalk正式发布,全源码、纯ArkTS编写
RainbowTalk是一套基于MobileIMSDK的产品级鸿蒙NEXT端IM系统,目前已正式发布。纯ArkTS、从零编写,无套壳、没走捷径,每一行代码都够“纯”(详见:《RainbowTalk详细介绍》)。 MobileIMSDK是一整套开源IM即时通讯框架,历经10年,超轻量级、高度提炼,一套API优雅支持 UDP 、TCP 、WebSocket 三种协议,支持 iOS、Android、H5、标准Java、小程序、Uniapp、鸿蒙NEXT,服务端基于Netty编写。
177 1
|
编译器
鸿蒙NEXT-鸿蒙三层架构搭建,嵌入HMRouter,实现便捷跳转,新手攻略。(2/3)
本文介绍在三层架构中实现模块依赖的步骤。首先在产品定制层(features)的oh-package.json5文件中导入共享包依赖,如"basic":"file:../../commons/basic"。然后在产品层(products)的配置文件中同时导入公共能力层和产品定制层的依赖,示例展示了如何添加"basic"和"my"两个依赖项。通过这些配置,三层架构的各模块之间建立了完整的依赖关系。
130 0
鸿蒙NEXT-鸿蒙三层架构搭建,嵌入HMRouter,实现便捷跳转,新手攻略。(2/3)
|
3月前
|
存储 开发者
鸿蒙Next仓颉开发语言中的数据类型总结分享
仓颉语言数据类型包括多种数字类型(Int、Float)、字符串(String)、数组(Array、ArrayList、ObservedArrayList)及HashMap。数字类型区分长度和精度,数组支持固定与动态操作,HashMap用于存储键值对。适合开发者快速掌握仓颉基础数据结构。#仓颉 #HarmonyOS
|
3月前
|
开发者
鸿蒙开发:资讯项目实战之项目初始化搭建
目前来说,我们的资讯项目只是往前迈了很小的一步,仅仅实现了项目创建,步虽小,但概念性的知识很多,这也是这个项目的初衷,让大家不仅仅可以掌握日常的技术开发,也能让大家理解实际的项目开发知识。
鸿蒙开发:资讯项目实战之项目初始化搭建
|
3月前
|
容器
HarmonyOS NEXT仓颉开发语言实战案例:外卖App
仓颉语言实战分享,教你如何用仓颉开发外卖App界面。内容包括页面布局、导航栏自定义、搜索框实现、列表模块构建等,附完整代码示例。轻松掌握Scroll、List等组件使用技巧,提升HarmonyOS应用开发能力。
|
3月前
|
缓存 JavaScript IDE
鸿蒙开发:基于最新API,如何实现组件化运行
手动只是让大家了解切换的原理,在实际开发中,可不推荐手动,下篇文章,我们将通过脚本或者插件,快速实现组件化模块之间的切换,实现独立运行,敬请期待!
120 0
鸿蒙开发:基于最新API,如何实现组件化运行
|
3月前
|
存储 IDE 定位技术
【HarmonyOS 5】鸿蒙组件&模板服务详解 - 助力高效开发的利器
在移动应用开发领域,效率与质量始终是开发者追求的核心目标。鸿蒙系统作为新兴的操作系统,为开发者提供了丰富且强大的开发资源,其中鸿蒙组件&模板服务更是成为开发者快速构建高质量应用的得力助手。
128 0
|
3月前
|
容器
HarmonyOS NEXT仓颉开发语言实战案例:健身App
本期分享一个健身App首页的布局实现,顶部采用Stack容器实现重叠背景与偏移效果,列表部分使用List结合Scroll实现可滚动内容。代码结构清晰,适合学习HarmonyOS布局技巧。