鸿蒙开发中父子组件如何进行数据通信(状态管理v1版)?

2025-01-03 10:57:44
39次阅读
0个评论

【问题描述】:我们经常在开发的时候,需要在父子组件进行数据的传递,有哪几种常见的用法?

【解决方案】:以下几种解决方案可以满足70%的应用场景。

一、@state 和 @prop

1.@State:装饰的变量值修改时,页面也会随之更新

2.@Prop: 配合@State使用,实现页面单向传递 数据从父组件传入子组件,父组件数据修改,子组件UI更新;在子组件中修改,父组件ui不更新 (传递值时使用this.)

代码示例

父组件


import  Child from '../view/Child'//引入子组件
@Entry
@Component
struct Index {
  @State showNumber2:number=0
  build() {
    Column() {
      Row() {
        Text('showNumber2:'+this.showNumber2)
          .fontSize(40)
      }
      .width('100%')
      Row() {
      Button('加1').width('100%').height(50).onClick(()=>{
        this.showNumber2++
      })
      }
      .width('100%')
      //子组件
      Row(){
        Child({
          showNumber2:this.showNumber2,
          //由于@Prop装饰器是单向传递 所以可以使用回调函数的方式来修改父组件的值
          giveIndex:(data)=>{
            if(data){
              this.showNumber2=parseInt(data)
            }else {
              this.showNumber2=0
            }
        }})
      }.width('100%')
    }
    .height('100%')
    .width('100%')

  }
}

子组件


@Component
export default struct Child {
  @Prop showNumber2:number
  // 回调函数
  giveIndex=(data)=>{
  }
  build() {
    Column() {
      Row() {
        Text('@Prop装饰器:')
        TextInput({text:JSON.stringify(this.showNumber2)})
          .width('100%')
          .type(InputType.Number)
          .height(50)
          .onChange((value)=>{
            //使用回调可以修改父组件的值
            //this.giveIndex(value)
            //传入修改无效
            if(value){
              this.showNumber2=parseInt(value)
            }else  {
              this.showNumber2=0
            }
          })
      }
      .width('50%')
    }
  }
}


二、@state 和 @Link:

配合@State使用,子组件用@Link接收, 可以实现页面双向传递 数据从父组件传入子组件,在子组件中修改则父组件ui更新 (传递值时使用$)

父组件

import  Child from '../view/Child'//引入子组件
@Entry
@Component
struct Index {
  @State showNumber1:number=0
  build() {
    Column() {
      Row() {
        Text('showNumber1:'+this.showNumber1)
          .fontSize(40)
      }
      .width('100%')
      Row() {
      Button('加1').width('100%').height(50).onClick(()=>{
        this.showNumber1= this.showNumber1+1
      })
      }
      .width('100%')
      Row(){
        Child({showNumber1:$showNumber1}) //注意这里传参是用的$
      }.width('100%')
    }
    .height('100%')
    .width('100%')

  }
}


子组件


@Component
export default struct Child {
  @Link showNumber1:number
  build() {
    Column() {
      Row() {
        Text('@Link装饰器:')
        TextInput({text:JSON.stringify(this.showNumber1)})
          .width('100%')
          .type(InputType.Number)
          .height(50)
          .onChange((value)=>{
            if(value){
              this.showNumber1=parseInt(value)
            }else  {
              this.showNumber1=0
            }
          })
      }
      .width('50%')
    }
  }
}


三 、@Provide 和 @Consume

1、@Provide/@Consume 配套使用,可以跨组件传值并且双向同步,在调用组件时不需要传递参数,能直接获取,ui更新 (不需要再组件调用中传值)

2、不同于上文提到的父子组件之间通过命名参数机制传递,@Provide和@Consume摆脱参数传递机制的束缚,实现跨层级传递 父组件:

import  Child from '../view/Child'//引入子组件
@Entry
@Component
struct Index {
  @Provide showNumber: number = 0
  build() {
    Column() {
      Row() {
        Text('showNumber:'+this.showNumber)
          .fontSize(40)
      }
      .width('100%')
      Row() {
      Button('加1').width('100%').height(50).onClick(()=>{
        this.showNumber= this.showNumber+1
      })
      }
      .width('100%')
      Row(){
        Child() // 子组件
      }.width('100%')
    }
    .height('100%')
    .width('100%')

  }
}

子组件:


@Component
export default struct Child {
@Consume showNumber:number
  build() {
    Column() {
      Row() {
        Text('@Provide装饰器:')
        TextInput({text:JSON.stringify(this.showNumber)})
          .width('100%')
          .type(InputType.Number)
          .height(50)
          .onChange((value)=>{
            if(value){
              this.showNumber=parseInt(value)
            }else  {
              this.showNumber=0
            }
          })
      }
      .width('50%')
    }
  }
}


四 、@Watch装饰器:状态变量更改通知

@Watch应用于对状态变量的监听。如果开发者需要关注某个状态变量的值是否改变,可以使用@Watch为状态变量设置回调函数

@Component
struct Child {
  @Prop @Watch('onCountUpdated') count: number = 0;
  @State total: number = 0;
  // @Watch 回调
  onCountUpdated(propName: string): void {
    this.total += this.count;
  }

  build() {
    Text(`Total: ${this.total}`)
  }
}

@Entry
@Component
struct Index {
  @State count: number = 0;

  build() {
    Column() {
      Button('add to basket')
        .onClick(() => {
          this.count++
        })
      Child({ count: this.count })
    }
  }
}


五、@Observed装饰器和@ObjectLink装饰器:嵌套类对象属性变化

对象嵌套两层之后,状态更新失去了响应性,这时候需要用到@Observed装饰器和@ObjectLink装饰器

// Index.ets
// Child
@Observed
class objA {
  public c: string;

  constructor(c: string) {
    this.c = c;
  }
}
@Observed
class objB {
  public a: objA;
  public b: string;

  constructor(a: objA, b: string) {
    this.a = a;
    this.b = b;
  }
}
@Component
struct Child {
  @ObjectLink a:objA
  build() {
    Text(this.a.c).fontSize(50)
      .onClick(()=>{
        this.a.c = 'ca';  
      })
  }
}
@Entry
@Component
struct Index {
  @State b: objB = new objB(new objA('a'),'b');
  build() {
    Column(){
      Child({a:this.b.a})
    }
    .width('100%')
    .onClick(()=>{
      this.b.a.c='pa'
    })
  }
}

点击父元素,可以实现给b.a.c赋值’pa’;

点击子组件,可以实现给a.c 赋值 ‘ca’

收藏00

登录 后评论。没有帐号? 注册 一个。