[二、状态管理]2管理组件拥有的状态(2)@Prop装饰器:父子单向同步

news/2024/11/17 11:24:48/文章来源:https://www.cnblogs.com/strengthen/p/18273993

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

说明

从API version 9开始,该装饰器支持在ArkTS卡片中使用。

概述

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

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

限制条件

@Prop装饰器不能在@Entry装饰的自定义组件中使用。

装饰器使用规则说明

@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,示例请参考父组件@State到子组件@Prop简单数据类型同步。
  • 当父组件的状态变量为数组时,@Prop装饰的变量和父组件状态变量的数组项类型相同,即@Prop : S和@State : Array<S>,示例请参考父组件@State数组中的项到子组件@Prop简单数据类型同步;
  • 当父组件状态变量为Object或者class时,@Prop装饰的变量和父组件状态变量的属性类型相同,即@Prop : S和@State : { propA: S },示例请参考从父组件中的@State类对象属性到@Prop简单类型的同步。

被装饰变量的初始值

允许本地初始化。

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

传递/访问

说明

从父组件初始化

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

用于初始化子组件

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

是否支持组件外访问

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

图1 初始化规则图示

观察变化和行为表现

观察变化

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

  • 当装饰的类型是允许的类型,即string、number、boolean、enum类型都可以观察到的赋值变化;
    // 简单类型
    @Prop count: number;
    // 赋值的变化可以被观察到
    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装饰的本地的修改将被父组件的更新覆盖。
 
说明

@Prop装饰的数据更新依赖其所属自定义组件的重新渲染,所以在应用进入后台后,@Prop无法刷新,推荐使用@Link代替。

使用场景

父组件@State到子组件@Prop简单数据类型同步

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

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

@Component
struct CountDownComponent {@Prop count: number;costOfOneAttempt: number = 1;build() {Column() {if (this.count > 0) {Text(`You have ${this.count} Nuggets left`)} else {Text('Game over!')}// @Prop装饰的变量不会同步给父组件Button(`Try again`).onClick(() => {this.count -= this.costOfOneAttempt;})}}
}@Entry
@Component
struct ParentComponent {@State countDownStartValue: number = 10;build() {Column() {Text(`Grant ${this.countDownStartValue} nuggets to play.`)// 父组件的数据源的修改会同步给子组件Button(`+1 - Nuggets in New Game`).onClick(() => {this.countDownStartValue += 1;})// 父组件的修改会同步给子组件Button(`-1  - Nuggets in New Game`).onClick(() => {this.countDownStartValue -= 1;})CountDownComponent({ count: this.countDownStartValue, costOfOneAttempt: 2 })}}
}

在上面的示例中:

  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。

@Component
struct Child {@Prop value: number;build() {Text(`${this.value}`).fontSize(50).onClick(()=>{this.value++})}
}@Entry
@Component
struct Index {@State arr: number[] = [1,2,3];build() {Row() {Column() {Child({value: this.arr[0]})Child({value: this.arr[1]})Child({value: this.arr[2]})Divider().height(5)ForEach(this.arr, item => {Child({'value': item} as Record<string, number>)}, item => item.toString())Text('replace entire arr').fontSize(50).onClick(()=>{// 两个数组都包含项“3”。this.arr = this.arr[0] == 1 ? [3,4,5] : [1,2,3];})}}}
}

 

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

如果点击界面上的“1”六次、“2”五次、“3”四次,将所有变量的本地取值都变为“7”。

7
7
7
----
7
7
7

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

3
4
5
----
7
4
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图书对象。 

class Book {public title: string;public pages: number;public readIt: boolean = false;constructor(title: string, pages: number) {this.title = title;this.pages = pages;}
}@Component
struct ReaderComp {@Prop title: string;@Prop readIt: boolean;build() {Row() {Text(this.title)Text(`... ${this.readIt ? 'I have read' : 'I have not read it'}`).onClick(() => this.readIt = true)}}
}@Entry
@Component
struct Library {@State book: Book = new Book('100 secrets of C++', 765);build() {Column() {ReaderComp({ title: this.book.title, readIt: this.book.readIt })ReaderComp({ title: this.book.title, readIt: this.book.readIt })}}
}

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

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

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

  • @Prop customCounter没有本地初始化,所以需要父组件提供数据源去初始化@Prop,并当父组件的数据源变化时,@Prop也将被更新;
  • @Prop customCounter2有本地初始化,在这种情况下,@Prop依旧允许但非强制父组件同步数据源给@Prop。
    @Component
    struct MyComponent {@Prop customCounter: number;@Prop customCounter2: number = 5;build() {Column() {Row() {Text(`From Main: ${this.customCounter}`).fontColor('#ff6b6565').margin({ left: -110, top: 12 })}Row() {Button('Click to change locally !').width(288).height(40).margin({ left: 30, top: 12 }).fontColor('#FFFFFF,90%').onClick(() => {this.customCounter2++})}Row() {Text(`Custom Local: ${this.customCounter2}`).fontColor('#ff6b6565').margin({ left: -110, top: 12 })}}}
    }@Entry
    @Component
    struct MainProgram {@State mainCounter: number = 10;build() {Column() {Row() {Column() {// customCounter必须从父组件初始化,因为MyComponent的customCounter成员变量缺少本地初始化;此处,customCounter2可以不做初始化。MyComponent({ customCounter: this.mainCounter })// customCounter2也可以从父组件初始化,父组件初始化的值会覆盖子组件customCounter2的本地初始化的值MyComponent({ customCounter: this.mainCounter, customCounter2: this.mainCounter })}}Row() {Column() {Button('Click to change number').width(288).height(40).margin({ left: 30, top: 12 }).fontColor('#FFFFFF,90%').onClick(() => {this.mainCounter++})}}}}
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/741801.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SQL漏洞--简介及数字型注入

数据库注入漏洞主要指开发人员在构建代码时,没有对输入边界进行安全考虑,导致攻击者可以通过合法的输入点提交一些精心构造的语句,从而欺骗后台数据库对其进行执行,导致数据库信息泄露的一种漏洞。 一、数字型注入: 通过pikachu搭建的靶场进行SQL数字型注入测试:一、 数字…

易优eyoucms标签ad报错:该广告ID(5)不存在

标签ad报错:该广告ID(5)不存在 错误原因: 把广告管理里面的广告删除导致 解决方法: 重新添加广告 在修改模板里面的广告位id本文来自博客园,作者:黄文Rex,转载请注明原文链接:https://www.cnblogs.com/hwrex/p/18294555

12bit 两通道5.2G或单通道10.4G pcie采集卡

12bit 两通道5.2G或单通道10.4G pcie采集卡是一款同时支持交流耦合与双极性宽带信号输入的高精度高速数据采集卡,它提供12位双通道5.2GS/s或单通道10.4GS, A/D采样变换,全功率模拟带宽(-3 dB)8GHz。板载FPGA具备实时信号处理能力,板载DDR4内存容量达8GB,可以进行大数据量…

易优CMS网站导入指定模板文件

基础用法] 标签:include描述:导入指定模板文件 用法:{eyou:include file="header.htm" /}属性: file= 指定模板文件路径 涉及标字段: 无 示例:在首页模板index.htm引入公共头部模板文件,可以使用include标签调用{eyou:include file="header.htm" /}…

你真的懂多线程吗?多线程 并行处理 CPU 操作系统

了解多线程、并行处理首先需要了解什么CPU、CPU核数、操作系统CPU物理数 即电脑拥有的物理CPU数量,普通电脑一般只有一个CPU插槽,也就是只有一个物理CPU。我们日常说的CPU,就是指封装好的一个物理CPU,作为商品进行售卖。但在编程讨论时,某些情况下,我们说的CPU含义又是指…

易优cms网站后台登录不上

请仔细检查以下问题: 1、磁盘空间大小是否100%; 2、站点目录权限是否为755; 3、站点所有目录的权限,禁止用root:root; 4、如还没解决,请联系技术支持本文来自博客园,作者:黄文Rex,转载请注明原文链接:https://www.cnblogs.com/hwrex/p/18294466

THM-Skynet-Writeup

通过学习相关知识点:攻破Linux目标机器并完成提权操作。部署并渗透目标机器 step1 使用Nmap扫描端口 nmap -p- -sC -sV -T4 -v 10.10.164.81139/445端口开放,可知目标机开启了SMB服务枚举SMB共享 smbclient -L \\10.10.164.81获取到一些可能能访问的SMB服务账号:anonymous、…

CAD可以转成PDF吗?有哪些转换的方法?

在CAD制图过程中,我们可能会遇到这样的问题:完成CAD制图后,为了方便阅览,经常会直接输出成PDF格式,输出完成后,打开一看,发现和原来的图纸差距很大,输出PDF文字显示不全,遇到这种情况该如何处理呢?给大家分享2个CAD转PDF的好用的转换方法。 方法一:使用转换工具 ilo…

易优cms安装数据库提示写入表ey_archives记录失败,请刷新重试

清空数据库,重新试试!不行清空后可以切换下其它版本的数据库。 实在因为空间环境问题,可以直接导入数据库方法安装,然后改下网站配置文件就可以了。补充:有一种特殊情况是防火墙拦截了, 还有一种可能是空间满了, 需要挨个排查一下。本文来自博客园,作者:黄文Rex,转载…

易优cms网站友情链接,设置新窗口打开无效

<a href="{$field.url}" {$field.target} target="_blank" title="{$field.title}">{$field.title}</a>在模板里面 友情链接里面得A标签里面添加{$field.target} 标签 即可 {eyou:flink type=text row=100 titlelen=20} <a href=…

jpg格式图片如何转换成pdf文件?

图片可以转换成PD吗?你们都是怎么转换的?用了什么转换器呢?要将jpg格式转换成PDF,说难不难,说简单也不简单,没有转换不了的格式,只有不好用的转换器罢了。下面来给大家介绍几个能将jpg转换成pdf的简单方法,能快速帮你实现转换哦! 方法一:在线工具进行转换 ilovepdf中…

全英文计算机科学速成班概况

早期计算 为我们展示了 早期计算机计算发展史 1)机械计算时期:算盘(起源于中国 or 美索不达米亚) 航海仪,星象表, 时钟....使得计算更加简便。 往往是需求产生计算动力要求。这么来看其实算盘的计算能力挺强的,中国古代貌似一直在使用算盘。 2)近代-电子和机械计算: co…