Harmony状态管理@Local和@Param

Harmony 状态管理 @Local 和 @Param

@Local 背景

@Localharmony应用开发中的v2版本中 对标**@State**的状态管理修饰器,它解决了 @State 对状态变量更改的检测混乱的问题:

  1. @State 修饰的状态变量 可以是组件内部自己定义的
  2. @State 修饰的状态 也可以由外部父组件传递

这样就导致了状态数据来源不唯一,在大型项目中会引发难易检测和维护状态的问题。如以下代码:

typescript 复制代码
@Entry
@Component
struct Index {
  @State num: number = 100

  build() {
    Column() {
      Text("父组件的数据 " + this.num)

      Son({ num: this.num })
      Son()
    }
    .height('100%')
    .width('100%')
  }
}

@Component
struct Son {
  @State num: number = 0

  build() {
    Column() {
      Button(`子组件 ${this.num}`)
        .onClick(() => {
          this.num++
        })
    }
  }
}

@Local 基本使用

@Local的出现就是为了解决这一类问题

  1. @Local 只能用在 @Componentv2 修饰的组件上
  2. 被**@Local**装饰的变量无法从外部初始化(无法由父组件传递进来),因此必须在组件内部进行初始化

我们对上面代码稍作修改

typescript 复制代码
@Entry
@Component
struct Index {
  @State num: number = 100

  build() {
    Column() {
      Text("父组件的数据 " + this.num)

      Son({ num: this.num }) // 这里就报错啦

      Son()
    }
    .height('100%')
    .width('100%')
  }
}

@ComponentV2 // 此处调整为 @ComponentV2
struct Son {

  // 此处调整为 @Local
  @Local num: number = 0

  build() {
    Column() {
      Button(`子组件 ${this.num}`)
        .onClick(() => {
          this.num++
        })
    }
  }
}

@Local与@State对比

@State @Local
参数 无。 无。
从父组件初始化 可选。 不允许外部初始化。
观察能力 能观测变量本身以及一层的成员属性,无法深度观测。 能观测变量本身,深度观测依赖@Trace装饰器。
数据传递 可以作为数据源和子组件中状态变量同步。 可以作为数据源和子组件中状态变量同步。

@Local 特别注意

  • @Local支持观测number、boolean、string、Object、class等基本类型以及Array、Set、Map、Date等内嵌类型。
  • @Local的观测能力仅限于被装饰的变量本身。当装饰简单类型时,能够观测到对变量的赋值;当装饰对象类型时,仅能观测到对对象整体的赋值;当装饰数组类型时,能观测到数组整体以及数组元素项的变化;当装饰Array、Set、Map、Date等内嵌类型时,可以观测到通过API调用带来的变化。

@Params

@Params 主要表示 子组件 接收父组件传递的数据。可以和 @Local 搭配一起使用

@Params 背景

在V1版本的状态管理修饰符中,可以用来处理 父子传参的技术有:

  1. 普通属性,不需要特别的修饰符 , 不具备单向同步
  2. @Prop 单向同步,不能监听深层次属性的改变,也不能做到双向同步
  3. @Link 可以做到双向同步,但是不能监听深层次属性的改变,而且不能直接用在 列表渲染技术 - ForEach 中
  4. @ObjectLink 可以做到双向同步,但是必须和 @Observed 搭配使用 ,而且只能用在自定义组件上

1. 普通属性

普通属性,不需要特别的修饰符 , 不具备单向同步

typescript 复制代码
@Entry
@Component
struct Index {
  @State num: number = 100

  build() {
    Column() {
      // 父组件传递过去的数据
      Son({ num: this.num })
        .onClick(() => {
          this.num++
          console.log("", this.num)
        })
    }
    .height('100%')
    .width('100%')
  }
}

@Component
struct Son {
  num: number = 0

  build() {
    Column() {
      Button(`子组件 ${this.num}`)
    }
  }
}

2. @Prop 单向同步

@Prop 单向同步

  1. 不能监听深层次属性的改变
  2. 也不能做到双向同步

在上面代码基础上 加入**@Prop**,可以检测到基本类型数据的更新

scss 复制代码
@Component
struct Son {
  @Prop num: number = 0

但是无法检测深层次属性的改变,如

typescript 复制代码
class Animal {
  dog: Dog = {
    age: 100
  }
}

class Dog {
  age: number = 100
}

@Entry
@Component
struct Index {
  @State
  animal: Animal = new Animal()

  build() {
    Column() {
      // 父组件传递过去的数据
      Son({ dog: this.animal.dog })
        .onClick(() => {
          this.animal.dog.age++
          console.log("", this.animal.dog.age)
        })
    }
    .height('100%')
    .width('100%')
  }
}

@Component
struct Son {
  @Prop dog: Dog

  build() {
    Column() {
      Button(`子组件 ${this.dog.age}`)
    }
  }
}

@Link 用法和@Prop基本一致

可以做到双向同步,但是

  1. 不能监听深层次属性的改变

  2. 而且不能直接用在 列表渲染技术 - ForEach以下代码演示这个效果

    typescript 复制代码
    class Dog {
      age: number = 100
    }
    
    @Entry
    @Component
    struct Index {
      @State
      dogList: Dog [] = [new Dog(), new Dog(), new Dog(), new Dog()]
    
      build() {
        Column() {
          ForEach(this.dogList, (item: Dog) => {
            // 此处会报错  Assigning the attribute 'item' to the '@Link' decorated attribute 'dog' is not allowed. <ArkTSCheck>
            Son({ dog: item })
              .onClick(() => {
                item.age++
                console.log("", item.age)
              })
          })
    
        }
        .height('100%')
        .width('100%')
      }
    }
    
    @Component
    struct Son {
      @Link dog: Dog
    
      build() {
        Column() {
          Button(`子组件 ${this.dog.age}`)
        }
      }
    }

@ObjectLink 可以做到双向同步,但是必须和 @Observed 搭配使用 ,而且只能用在自定义组件

小结

可以看到,如果都是使用 v1版本的这一套 父子传参的技术,是十分复杂难易直接上手使用的。

@Params 介绍

Param表示组件从外部传入的状态,使得父子组件之间的数据能够进行同步:

  • @Param装饰的变量支持本地初始化,但是不允许在组件内部直接修改变量本身。
    • 如果不本地初始化,那么必须加入 @Require
  • @Param 可以做到单向同步
  • @Param 可以检测深层次属性的修改,但是该修改在数据源上必须是整体对象的更新
  • @Params 如果也想要深度监听单个属性的修改,那么需要使用 @ObservedV2@Trace

以下代码主要演示:@Param 可以检测深层次属性的修改,但是该修改在数据源上必须是整体对象的更新

typescript 复制代码
class Person {
  age: number = 100
}
@Entry
@ComponentV2
struct Index {
  @Local
  person: Person = new Person()
  build() {
    Column() {
      Son({ age: this.person.age })
        .onClick(() => {
          this.person.age++
          console.log("", this.person.age)
          if (this.person.age === 105) {
            const p = new Person()
            p.age = 200
            // 整体更新,子组件可以感知到
            this.person = p
          }
        })
    }
    .height('100%')
    .width('100%')
  }
}

@ComponentV2
struct Son {
  // 要么设置 @Require 表示父组件必须传递数据
  // 要么设置 默认值
  @Require @Param age: number
  build() {
    Column() {
      Button(`子组件 ${this.age}`)
    }
  }
}

总结

  1. @Local 可以看成是 @State的替代 ,单独表示组件内部的状态
  2. @Params 可以看成 @Prop @Link @ObjectLink的替代,更加严谨
  3. @Local 和 @Params 搭配一起使用,都只能用在 @Componentv2 修饰的自定义组件上
相关推荐
一只栖枝2 小时前
华为 HCIE 大数据认证中 Linux 命令行的运用及价值
大数据·linux·运维·华为·华为认证·hcie·it
zhanshuo5 小时前
在鸿蒙里优雅地处理网络错误:从 Demo 到实战案例
harmonyos
zhanshuo6 小时前
在鸿蒙中实现深色/浅色模式切换:从原理到可运行 Demo
harmonyos
whysqwhw11 小时前
鸿蒙分布式投屏
harmonyos
whysqwhw12 小时前
鸿蒙AVSession Kit
harmonyos
whysqwhw14 小时前
鸿蒙各种生命周期
harmonyos
whysqwhw15 小时前
鸿蒙音频编码
harmonyos
whysqwhw15 小时前
鸿蒙音频解码
harmonyos
whysqwhw15 小时前
鸿蒙视频解码
harmonyos
whysqwhw15 小时前
鸿蒙视频编码
harmonyos