最近终于把项目升级到了鸿蒙的最新版本,其中最大的感受就是——状态管理V2版本真香!不过,在说V2之前,得先回顾一下V1的那些事,有对比才有伤害!

一、V1版本的装饰器:简单但有限

   在V1版本里,鸿蒙的状态管理主要依靠几个核心的装饰器,比如@State、@Prop、@Link、@Provide/@Consume、@Observed等。它们虽然能满足基本的开发需求,但在一些复杂场景下就显得有些力不从心了。

@State:用于声明组件的状态变量,但跨组件共享状态不够方便。
V1代码示例:

// 组件A
@State countA: number = 0;

// 组件B(子组件)
@Consume countConsume: number = this.countA; // 需要通过@Provide和@Consume共享状态

@Prop:用于父子组件传值,但只能单向传递。
V1代码示例:

// 父组件
@State title: string = '标题';

// 子组件
@Prop titleProp: string = this.title; // 子组件无法直接修改titleProp

@Link:用于连接父子组件的状态,但实现方式较为繁琐。
V1代码示例:

// 父组件
@State parentCount: number = 0;

// 子组件
@Link(from: 'parentCount', to: 'childCount')
@State childCount: number = 0; // 需要通过@Link连接父子组件状态

@Provide和@Consume:用于跨组件共享状态,但层级较深时维护起来比较麻烦。
V1代码示例:

// 祖先组件
@Provide sharedState: { data: string } = { data: '共享数据' };

// 后代组件
@Consume sharedStateConsume: { data: string } = this.sharedState; // 后代组件消费状态

@Observed:用于观测对象的变化,但观测深度有限。
V1代码示例:

@Observed user: { name: string; address: { city: string } } = { name: '张三', address: { city: '北京' } };

// 修改嵌套对象的属性,有时界面不会自动更新
this.user.address.city = '上海'; // 可能不会触发界面更新

二、V2版本的装饰器:全面升级,更加强大

升级到V2版本后,鸿蒙的状态管理进行了全面的升级和优化。不仅保留了V1版本的核心装饰器,还引入了一些新的特性和改进。

@State:状态管理更便捷

在V2版本里,@State装饰器得到了加强,不仅支持组件内部的状态管理,还支持跨组件共享状态。

// 组件A
@State countA: number = 0; // 声明一个状态变量countA

// 组件B(子组件)
@Consume countConsume: number = this.countA; // 直接消费组件A的countA,无需@Provide

@Prop:父子传值更灵活
V2版本的@Prop装饰器支持双向绑定和单向绑定两种模式。

// 父组件
@State title: string = '默认标题';

// 子组件
@Prop(sync: true) titleProp: string = this.title; // 支持双向绑定

// 子组件中修改titleProp的值
this.titleProp = '新的标题'; // 父组件的title也会同步更新

@Link:状态连接更直观
V2版本的@Link装饰器实现方式更加直观。

// 父组件
@State parentCount: number = 0;

// 子组件
@Link(from: 'parentCount', to: 'childCount')
@State childCount: number = 0; // 更直观的连接父子组件状态

@Provide和@Consume:状态共享更高效
V2版本的@Provide和@Consume装饰器支持任意组件之间的状态共享。

// 任意组件A
@Provide sharedState: { data: string } = { data: '共享数据' };

// 任意组件B
@Consume sharedStateConsume: { data: string } = this.sharedState; // 任意组件都可以消费状态

@Observed:对象观测更全面
V2版本的@Observed装饰器观测深度更深。

@Observed user: { name: string; address: { city: string } } = { name: '张三', address: { city: '北京' } };

// 修改嵌套对象的属性,界面会自动更新
this.user.address.city = '上海'; // 界面会自动更新

总的来说,鸿蒙状态管理V2版本在V1版本的基础上进行了全面的升级和优化。特别是@State、@Prop、@Link、@Provide/@Consume以及@Observed这些装饰器的改进,让状态管理变得更加便捷、灵活和高效。

继续深入,聊聊那些可能被忽略,但却非常实用的装饰器们。

在V1版本里,除了之前提到的那些核心装饰器外,还有一些装饰器虽然不那么显眼,但在特定场景下却能发挥大作用。

@local:用于声明局部变量,避免与全局状态冲突。
V1代码示例:

@Entry
struct MyComponent {
  @State globalCount: number = 0;

  build() {
    Column() {
      // 使用@local声明局部变量,避免与全局状态冲突
      @local localCount: number = 0;

      Button('增加全局计数')
        .onClick(() => {
          this.globalCount++;
        })
      Button('增加局部计数')
        .onClick(() => {
          localCount++; // 操作的是局部变量,不会影响全局状态
        })
      Text(`全局计数:${this.globalCount},局部计数:${localCount}`)
    }
  }
}

@param:用于声明函数参数,提高代码可读性。
V1代码示例:

function addNumbers(@param a: number, @param b: number): number {
  return a + b;
}

// 调用函数时,参数名会作为提示显示
let result = addNumbers(2, 3);

@once:用于声明只执行一次的函数,避免重复执行。
V1代码示例:

@Entry
struct MyComponent {
  @State count: number = 0;

  @once
  init() {
    console.log('初始化函数只执行一次');
    this.count = 10;
  }

  build() {
    Column() {
      Button('增加计数')
        .onClick(() => {
          this.count++;
          this.init(); // 即使多次点击,init函数也只执行一次
        })
      Text(`计数:${this.count}`)
    }
  }
}

@Event:用于声明自定义事件,实现组件间通信。
V1代码示例:

// 子组件
@Entry
struct ChildComponent {
  @Event onButtonClick: () => void;

  build() {
    Button('点击我')
      .onClick(() => {
        this.onButtonClick(); // 触发自定义事件
      })
  }
}

// 父组件
@Entry
struct ParentComponent {
  build() {
    Column() {
      ChildComponent()
        .onButtonClick(() => {
          console.log('按钮被点击了'); // 父组件监听子组件的自定义事件
        })
    }
  }
}

@monitor:用于监听对象的变化,实现深度观测。
V1代码示例:

@Entry
struct MyComponent {
  @State user: { name: string; age: number } = { name: '张三', age: 20 };

  @monitor
  onUserChange(newValue: { name: string; age: number }, oldValue: { name: string; age: number }) {
    console.log('用户信息发生变化:', newValue, oldValue);
  }

  build() {
    Column() {
      Button('修改用户信息')
        .onClick(() => {
          this.user = { name: '李四', age: 25 }; // 修改用户信息,触发onUserChange函数
        })
    }
  }
}

@Computed:用于声明计算属性,基于其他状态自动生成值。
V1代码示例:

@Entry
struct MyComponent {
  @State firstName: string = '张';
  @State lastName: string = '三';

  @Computed
  get fullName(): string {
    return `${this.firstName}${this.lastName}`; // 计算属性fullName基于firstName和lastName自动生成
  }

  build() {
    Column() {
      Text(`全名:${this.fullName}`)
    }
  }
}

二、V2版本的装饰器

升级到V2版本后,这些装饰器也得到了相应的升级和优化,使用起来更加方便和强大。

@local:在V2版本中,@local装饰器的使用方式更加灵活。

function addNumbers(@param a: number, @param b: number): number {
  return a + b;
}

// 如果传入非数字类型的参数,会在编译时报错
let result = addNumbers(2, '3'); // 编译错误:参数b必须是number类型

@once:在V2版本中,@once装饰器的实现方式更加高效。

@Entry
struct MyComponent {
  @State count: number = 0;

  @once
  init() {
    console.log('初始化函数只执行一次');
    this.count = 10;
  }

  build() {
    Column() {
      Button('增加计数')
        .onClick(() => {
          this.count++;
          this.init(); // 即使多次点击,init函数也只执行一次
        })
      Text(`计数:${this.count}`)
    }
  }
}

@Event:在V2版本中,@Event装饰器支持更多的事件类型。

// 子组件
@Entry
struct ChildComponent {
  @Event onButtonClick: () => void;
  @Event onDataChange: (newData: string) => void;

  build() {
    Column() {
      Button('点击我')
        .onClick(() => {
          this.onButtonClick(); // 触发自定义事件
        })
      TextInput()
        .onChange((value) => {
          this.onDataChange(value); // 触发带参数的自定义事件
        })
    }
  }
}

// 父组件
@Entry
struct ParentComponent {
  build() {
    Column() {
      ChildComponent()
        .onButtonClick(() => {
          console.log('按钮被点击了');
        })
        .onDataChange((newData) => {
          console.log('数据发生变化:', newData);
        })
    }
  }
}

@monitor:在V2版本中,@monitor装饰器支持更细粒度的监听。

@Entry
struct MyComponent {
  @State user: { name: string; age: number } = { name: '张三', age: 20 };

  @monitor('name')
  onUserNameChange(newValue: string, oldValue: string) {
    console.log('用户名发生变化:', newValue, oldValue);
  }

  @monitor('age')
  onUserAgeChange(newValue: number, oldValue: number) {
    console.log('用户年龄发生变化:', newValue, oldValue);
  }

  build() {
    Column() {
      Button('修改用户信息')
        .onClick(() => {
          this.user = { name: '李四', age: 25 }; // 修改用户信息,触发对应的监听函数
        })
    }
  }
}

@Computed:在V2版本中,@Computed装饰器支持更复杂的计算逻辑。

@Entry
struct MyComponent {
  @State price: number = 100;
  @State quantity: number = 2;

  @Computed
  get total(): number {
    return this.price * this.quantity; // 计算属性total基于price和quantity自动生成
  }

  @Computed
  get discount(): number {
    return this.total > 200 ? this.total * 0.1 : 0; // 更复杂的计算逻辑
  }

  build() {
    Column() {
      Text(`总价:${this.total},折扣:${this.discount}`)
    }
  }
}

状态管理是构建动态交互应用的核心机制,而鸿蒙系统的装饰器模式为开发提供了高效、灵活的工具集。通过合理使用@State、@Prop、@Link等装饰器,开发者可以清晰定义数据流方向,实现组件间的高效通信,同时避免深拷贝和冗余渲染的性能陷阱。随着应用复杂度的提升,装饰器模式的优势愈发凸显:它使代码结构更清晰,维护成本更低,且能灵活应对需求变化。

HarmonyOS应用开发工具##Ark-TS语言


Cydar
1 声望0 粉丝

跨越山海,终见曙光