引言

状态管理是前端开发中最核心的问题之一。无论是 React 的 useState/useEffect,Vue 的 ref/reactive,还是 Flutter 的 setState/Provider,每个框架都有自己的一套状态管理方案。HarmonyOS 在 ArkUI V1 中提供了一套基于装饰器的状态管理系统:@State@Prop@Link@Observed@ObjectLink 等。这套系统虽然功能完备,但在复杂场景下存在一些明显的痛点:

  1. 对象引用替换:V1 的 @Observed 只能追踪对象引用的变化,修改对象内部属性时需要整体替换对象(this.obj = this.obj.clone()),这在深层嵌套对象中非常繁琐。
  2. 粗粒度追踪@State 追踪的是整个变量的变化,即使只修改了对象的一个属性,也会触发整个组件树的重渲染。
  3. 装饰器繁杂@Prop@Link@ObjectLink@Consume@Provide 等多种装饰器,类型间差异细微,容易混淆。
  4. 缺少计算属性:V1 没有内置的计算属性机制,开发者只能通过手动编写 get 方法来实现派生状态,但这种方式没有缓存,每次访问都会重新计算。
  5. 缺乏声明式监听:想在状态变化时执行副作用,需要手动在 aboutToUpdate 等生命周期中编写回调逻辑。

为了应对这些问题,HarmonyOS NEXT 引入了V2 状态管理系统。这是一套全新的、基于细粒度追踪和声明式编程范式的状态管理方案,包含 10 余个新装饰器和 API:@ObservedV2@Trace@ComponentV2@Local@Param@Event@Once@Computed@MonitorAppStorageV2PersistenceV2 等。

本文将通过构建一个"响应式档案编辑器",深入讲解 V2 状态管理的核心概念。档案编辑器允许编辑姓名、年龄、角色,并实时展示派生数据(全名、年龄段),同时记录每次修改的操作日志——模拟了 @Monitor 的声明式监听效果。

读完本文你将能够:

  • 理解 V1 状态管理的痛点,以及 V2 如何解决它们
  • 掌握 @ObservedV2 + @Trace 的类级和属性级追踪机制
  • 理解 @ComponentV2 的组件模型及其与 V1 @Component 的区别
  • 了解 @Local@Param@Event@Computed@Monitor 的作用
  • 认识 AppStorageV2PersistenceV2 的全局状态方案
  • 知道 V1 与 V2 的兼容性问题及最佳实践

V1 状态管理的痛点回顾

在深入了解 V2 之前,我们先回顾 V1 状态管理中开发者常遇到的几个痛点。理解这些痛点,有助于你体会 V2 设计背后的动机。

痛点一:必须替换整个对象引用

V1 中,如果你想追踪一个对象内部属性的变化,必须用 @Observed 装饰类,用 @ObjectLink 在子组件中引用。而最繁琐的是——修改属性后,必须创建一个新的对象引用来替换旧的:

// V1 方式:需要整体替换对象
@Observed
class UserProfile {
  firstName: string;
  lastName: string;
  age: number;
  
  clone(): UserProfile {
    return new UserProfile(this.firstName, this.lastName, this.age);
  }
}

@Component
struct V1Editor {
  @State user: UserProfile = new UserProfile('李', '明', 32);
  
  updateFirstName(newName: string): void {
    // 必须创建新对象并替换
    let newUser = this.user.clone();
    newUser.firstName = newName;
    this.user = newUser;  // 整个替换
  }
}

每次修改一个字段都要 clone() + 修改 + 替换,代码冗长且容易遗漏。

痛点二:粗粒度重渲染

V1 中,对 @State 变量的任何修改都会触发整个组件及其子组件的重新渲染。如果一个 @State 对象包含 10 个属性,而只有一个 Text 组件绑定了其中一个属性,修改另 9 个属性也会导致这个 Text 组件重建——尽管它的内容没有变化。

痛点三:装饰器概念过多

V1 有近十个与状态相关的装饰器:@State@Prop@Link@ObjectLink@Provide@Consume@StorageLink@StorageProp@Watch。每个装饰器的语义、使用场景、数据流向都不同,开发者需要记忆大量规则。

痛点四:缺少计算属性和声明式监听

需要基于现有状态派生新数据时,只能写 getter 函数。需要监听状态变化时,只能在 aboutToUpdate 中手动比较新旧值来判定具体哪个属性变了。这在复杂业务场景中代码可读性较差。

V2 状态管理体系概览

V2 状态管理是一套重新设计的状态管理方案,核心思想是细粒度追踪声明式编程。以下是 V2 的核心组件:

装饰器/API 对应 V1 作用 用法位置
@ObservedV2 @Observed 类级装饰器,启用深度属性观察 class 定义
@Trace @Track 属性级装饰器,标记单个属性为可追踪 class 属性
@ComponentV2 @Component 组件装饰器,替代 V1 的 @Component struct 定义
@Local @State 组件内部状态 @ComponentV2 属性
@Param @Prop 外部传入参数 @ComponentV2 属性
@Event @Link(回调) 事件回调传递 @ComponentV2 属性
@Once 仅在初始化时设置一次 @ComponentV2 属性
@Computed —(手动 get) 计算属性,自动缓存派生值 @ComponentV2 get 方法
@Monitor @Watch 声明式状态变化监听器 @ComponentV2 方法
AppStorageV2 AppStorage 全局内存存储 全局
PersistenceV2 全局持久化存储 全局

这个表格是理解 V2 的"地图"。下面我们逐个深入讲解。

核心 API 逐项解析

@ObservedV2:类级观察

@ObservedV2 是 V2 状态管理的基础。它装饰一个 class,为这个类的所有 @Trace 属性建立观察机制。一旦被装饰,框架会在运行时追踪对 @Trace 属性的所有访问和修改。

@ObservedV2
class UserProfile {
  @Trace firstName: string;
  @Trace lastName: string;
  @Trace age: number;
  @Trace role: string;
  
  constructor(firstName: string, lastName: string, age: number, role: string) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.age = age;
    this.role = role;
  }
}

关键点:

  • @ObservedV2 必须与 @Trace 配合使用。一个类被 @ObservedV2 装饰后,只有标了 @Trace 的属性才会被追踪。
  • 没有被 @Trace 标记的属性,修改后不会触发 UI 更新。
  • 与 V1 @Observed 最大区别:不需要替换整个对象引用。直接修改 @Trace 属性即可触发更新。

@Trace:属性级追踪

@Trace 是 V2 精细化的核心。它标记类中的单个属性,使得框架能够精确追踪到"哪个属性被读取了"和"哪个属性被修改了"。

@ObservedV2
class Task {
  @Trace title: string = '';
  @Trace completed: boolean = false;
  @Trace priority: number = 0;
  description: string = '';  // 没有 @Trace,修改不触发 UI 更新
}

这种设计的优势是:只有依赖了被修改属性的组件才会重渲染。如果一个 Text 只绑定了 task.title,修改 task.priority 时这个 Text 不会重渲染。

@ComponentV2:新一代组件

@ComponentV2 是 V2 的组件装饰器,替代 V1 的 @Component。使用 @ComponentV2 的组件可以使用所有 V2 装饰器(@Local@Param@Event@Computed@Monitor 等),并且内置了更高效的变化检测机制。

@ComponentV2
struct ProfileCard {
  @Param user: UserProfile;
  @Local selected: boolean = false;
  
  @Computed
  get displayName(): string {
    return this.user.firstName + ' ' + this.user.lastName;
  }
  
  build() {
    Column() {
      Text(this.displayName)  // 只有 firstName/lastName 变化时才更新
      Text(this.user.role)    // 只有 role 变化时才更新
    }
  }
}

@ComponentV2 的 build 方法与 V1 @Component 语法相同,但内部渲染机制不同——它基于依赖追踪,而不是全部刷新。

@Local:组件内部状态

@Local 是 V2 中替代 @State 的装饰器,表示"这个状态属于当前组件,由组件自己管理"。语法与 @State 基本相同:

@ComponentV2
struct Counter {
  @Local count: number = 0;
  @Local name: string = '计数器';
  
  build() {
    Button(this.name + ': ' + this.count.toString())
      .onClick(() => { this.count++; })
  }
}

@State 的区别:

  • @Local 只能在 @ComponentV2 中使用。
  • @Local 支持任意类型,包括 @ObservedV2 装饰的类。这在 V1 中是被禁止的(@State 不能是 @ObservedV2 类型)。

@Param 和 @Event:父子组件通信

V2 用 @Param(输入)和 @Event(输出)替代了 V1 的 @Prop@Link,语义更加清晰——数据向下流动,事件向上冒泡:

@ComponentV2
struct ChildEditor {
  @Param name: string = '';
  @Param @Once initialId: string = '';  // @Once 表示只在初始化时设置
  @Event onNameChange: (newName: string) => void;
  
  build() {
    TextInput({ text: this.name })
      .onChange((value: string) => {
        this.onNameChange(value);  // 通过事件向父组件传值
      })
  }
}

父组件使用:

@ComponentV2
struct ParentPage {
  @Local userName: string = '张三';
  
  build() {
    ChildEditor({
      name: this.userName,
      onNameChange: (newName: string) => { this.userName = newName; }
    })
  }
}

这种模式的优势是:

  • 数据流单向:父 → @Param → 子组件;子组件 → @Event → 父组件。
  • @Event 本质是回调函数,子组件不需要知道父组件如何处理数据。
  • @Once 可以标记那些"只在创建时传入一次,后续不更新"的参数,优化渲染性能。

@Computed:计算属性

@Computed 是 V2 中最令人期待的新特性之一。它声明式地定义一个计算属性——当依赖的 @Trace 属性变化时自动重新计算,并且结果会被缓存,直到依赖再次变化:

@ComponentV2
struct UserSummary {
  @Param user: UserProfile;
  
  @Computed
  get displayName(): string {
    return this.user.firstName + ' ' + this.user.lastName;
  }
  
  @Computed
  get ageGroup(): string {
    if (this.user.age < 25) return '青年';
    if (this.user.age < 40) return '壮年';
    return '中年';
  }
  
  build() {
    Column() {
      Text(this.displayName)  // 依赖 firstName, lastName
      Text(this.ageGroup)     // 依赖 age
      Text(this.user.role)    // 依赖 role
    }
  }
}

关键行为:

  • displayName 只在 firstNamelastName 变化时重新计算。
  • ageGroup 只在 age 变化时重新计算。
  • 框架自动追踪 @Computed 访问了哪些 @Trace 属性,建立精确的依赖图。
  • 多次访问同一个 @Computed 属性,在依赖不变的情况下返回缓存值。

@Monitor:声明式监听

@Monitor 用于监听特定状态的变化并执行副作用。它替代了 V1 的 @Watch,但语义更加明确——不是在"属性被 watch",而是"方法作为 monitor":

@ComponentV2
struct Editor {
  @Local user: UserProfile = new UserProfile('', '', 0, '');
  
  @Monitor('user.firstName', 'user.lastName')
  onNameChange(): void {
    console.log('姓名已更新为: ' + this.user.displayName());
  }
  
  @Monitor('user.age')
  onAgeChange(): void {
    if (this.user.age < 0) {
      this.user.age = 0;  // 可以在这里做校验
    }
    console.log('年龄已更新为: ' + this.user.age);
  }
}

@Monitor 的第一个参数是需要监听的属性路径(支持点号分隔的多级路径)。当这些属性变化时,被装饰的方法自动执行。一个方法可以监听多个属性,多个方法也可以监听相同属性。

AppStorageV2 和 PersistenceV2:全局状态

V2 还升级了全局状态管理方案:

  • AppStorageV2:替代 V1 的 AppStorage。在 V2 中直接存储 @ObservedV2 对象,任意组件可以通过 AppStorageV2.connect() 建立双向绑定。
  • PersistenceV2:这是 V1 没有的全新 API,提供开箱即用的持久化存储。它自动将 @ObservedV2 对象序列化到本地磁盘,应用重启后自动恢复,支持复杂类型的自动序列化。
// 连接到全局存储
@Local settings: AppSettings = AppStorageV2.connect(AppSettings, 'app_settings')!;

// 持久化存储(自动保存到磁盘)
PersistenceV2.connect(UserPreferences, 'user_prefs');

V1 与 V2 的兼容性

这是一个很重要但容易被忽略的话题。V1 和 V2 的状态管理系统是两套独立的体系,不能混用:

操作 是否支持
V1 @Component 中使用 @State 支持
V1 @Component 中使用 @ObservedV2 类作为 @State 类型 不支持(编译错误)
V2 @ComponentV2 中使用 @Local 支持
V1 @Component 的 build() 中直接给 @ComponentV2@Param 赋值 不支持(编译错误)
@Entry + @Component 中嵌套 @ComponentV2(不传参) 支持但需注意边界
同一项目中同时存在 V1 和 V2 组件 支持

实践建议:如果你从零开始一个新项目,建议全部使用 V2;如果是在现有 V1 项目中引入 V2,建议保持隔离——一个页面要么全用 V1,要么全用 V2,避免交叉使用带来的兼容性问题。

Demo 设计:响应式档案编辑器

本文 Demo 实现了一个"响应式档案编辑器",由于 V1/V2 的兼容性限制(纯 V2 组件难以嵌入 V1 的 @Entry 页面),Demo 采用了 V1 组件 + 模拟 V2 概念的实现方式,但完整展示了 V2 的核心设计思想:

页面结构

Column(根容器)
├── Header(深色标题栏:"状态管理V2实验室" + @ObservedV2 + @Trace 标签)
├── Scroll
│   └── Column
│       ├── 响应式数据档案卡(展示 current 数据)
│       │   ├── 用户姓名 + 角色 + 年龄段
│       │   ├── 年龄大号显示
│       │   └── 点击卡片切换颜色(模拟绑定交互)
│       ├── 统计芯片行(更新次数 + 年龄分组 + 全名)
│       ├── 编辑属性区
│       │   ├── V2 直接修改说明文字
│       │   ├── 姓/名 TextInput(onChange 直接修改 @State 字段)
│       │   ├── 年龄 TextInput(数字输入)
│       │   ├── 角色显示
│       │   └── 三个操作按钮(应用更新 + 随机角色 + +1岁)
│       ├── V1 vs V2 对比表(10 行)
│       ├── V2 核心优势(5 条带编号的说明卡片)
│       ├── 操作日志区(模拟 @Monitor 效果)
│       └── V2 关键 API 参考
└── 根容器结束

5 个交互点

  1. 编辑姓/名:在 TextInput 中输入新值 → onChange 直接修改 this.firstName/this.lastName → 档案卡实时更新(模拟 @Trace 的直接赋值效果,这是 V2 对比 V1 最核心的改进)。
  2. 编辑年龄:在数字输入框中修改年龄 → this.age 直接更新 → 大号年龄数字实时变化 → 年龄段文字自动更新(模拟 @Computed 的计算属性效果)。
  3. 点击档案卡变色:点击档案卡 → 背景色在蓝色和粉色之间切换(演示状态驱动的 UI 变化)。
  4. 操作按钮:"应用更新"记录当前状态到日志;“随机角色"从 7 种预设角色中随机选取;”+1 岁"递增年龄并记录日志。
  5. 操作日志追踪:每次数据修改自动记录一条带时间戳的日志,模拟 @Monitor 的声明式监听——每次属性变化都触发日志追加。

核心实现

数据模型与状态定义

Demo 使用 V1 的 @State 分别存储每个字段,模拟了 V2 @Trace 的细粒度追踪——每个字段独立追踪,互不影响:

class UserProfile {
  firstName: string;
  lastName: string;
  age: number;
  role: string;

  constructor(firstName: string, lastName: string, age: number, role: string) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.age = age;
    this.role = role;
  }

  displayName(): string {
    return this.firstName + ' ' + this.lastName;
  }
}

@Entry
@Component
struct StateManagementV2Page {
  @State firstName: string = '李';
  @State lastName: string = '明';
  @State age: number = 32;
  @State role: string = '高级工程师';
  @State selected: boolean = false;
  @State logEntries: LogEntry[] = [];
  @State logIndex: number = 0;
  @State updateCount: number = 0;
  // ...
}

每个字段独立 @State,类似于每个字段独立 @Trace。修改 firstName 不会触发 age 相关视图的更新,实现了细粒度追踪的效果。

计算属性(模拟 @Computed)

Demo 通过 getter 方法模拟了 V2 @Computed 的行为:

getDisplayName(): string {
  return this.firstName + ' ' + this.lastName;
}

getAgeGroup(): string {
  if (this.age < 25) {
    return '青年';
  }
  if (this.age < 40) {
    return '壮年';
  }
  return '中年';
}

在 V2 的 @Computed 中,这些方法是自动缓存和自动追踪依赖的。在 V1 中,虽然每次访问都会重新计算(没有缓存),但依赖追踪是相同的——框架知道 getDisplayName() 依赖于 firstNamelastName,只有当这两个属性变化时,绑定了 getDisplayName()Text 才会更新。

直接赋值更新(模拟 @Trace)

V2 最大的卖点是"直接赋值,自动更新 UI"。Demo 中的所有数据修改都采用了这种模式:

// TextInput onChange 直接修改字段
.onChange((value: string) => {
  this.firstName = value;  // 直接赋值,UI 自动更新
})

// 按钮 onClick 直接修改字段
incrementAge(): void {
  this.age = this.age + 1;     // 直接修改
  this.updateCount = this.updateCount + 1;
  this.addLog('递增年龄: ' + this.age.toString() + '岁');
}

randomRole(): void {
  let idx: number = Math.floor(Math.random() * this.roles.length);
  this.role = this.roles[idx];  // 直接赋值
  this.updateCount = this.updateCount + 1;
  this.addLog('随机角色: ' + this.role);
}

在 V1 中,@State 的原始类型(string、number、boolean)本身就支持直接赋值触发更新。但如果是对象类型,V1 需要整体替换引用,而 V2 可以直接修改 @Trace 属性。Demo 通过使用原始类型的 @State 字段,展示了这种"直接修改"的便捷性。

操作日志(模拟 @Monitor)

每次修改属性时,Demo 自动记录一条日志。这模拟了 V2 @Monitor 的声明式监听:

addLog(event: string): void {
  let now: Date = new Date();
  let hStr: string = now.getHours() < 10 ? '0' + now.getHours().toString() : now.getHours().toString();
  let mStr: string = now.getMinutes() < 10 ? '0' + now.getMinutes().toString() : now.getMinutes().toString();
  let sStr: string = now.getSeconds() < 10 ? '0' + now.getSeconds().toString() : now.getSeconds().toString();
  let timeStr: string = hStr + ':' + mStr + ':' + sStr;
  this.logIndex = this.logIndex + 1;
  let newLogs: LogEntry[] = this.logEntries.slice();
  newLogs.unshift(new LogEntry(this.logIndex, event, timeStr));
  if (newLogs.length > 8) {
    newLogs.pop();
  }
  this.logEntries = newLogs;
}

日志保留最近 8 条,使用不可变更新模式(slice() + unshift() + pop())。在 V2 @Monitor 中,这些日志逻辑可以独立声明,与业务逻辑解耦:

// V2 中可以用 @Monitor 独立声明日志逻辑
@Monitor('firstName', 'lastName')
onNameChange(): void {
  this.addLog('姓名已更新');
}

@Monitor('age')
onAgeChange(): void {
  this.addLog('年龄已更新');
}

档案卡的响应式绑定

档案卡是 Demo 中展示 V2 响应式数据绑定的核心区域:

Column() {
  Text(this.getDisplayName())
    .fontSize(18)
    .fontColor('#FFFFFF')
    .fontWeight(FontWeight.Bold)
    .margin({ bottom: 4 })

  Text(this.role + ' · ' + this.getAgeGroup())
    .fontSize(12)
    .fontColor('#FFFFFFCC')
}
// ...
Column() {
  Text(this.age.toString())
    .fontSize(26)
    .fontColor('#FFFFFF')
    .fontWeight(FontWeight.Bold)
  Text('岁')
    .fontSize(10)
    .fontColor('#FFFFFF88')
}
// ...
.backgroundColor(this.selected ? '#D53F8C' : '#1677FF')
.onClick(() => {
  this.selected = !this.selected;
  this.addLog('点击档案卡');
})

卡片背景色随 selected 变化在蓝色和粉色之间切换——这是 V2 状态驱动的 UI 变化的典型示例。在 V2 中,这个切换由框架自动管理依赖追踪:backgroundColor 依赖于 selected,只有 selected 变化时才会重新计算。

V1 vs V2 对照表

Demo 中实现了一张 10 行的对照表,帮助开发者直观理解 V1 和 V2 的映射关系:

特性 V1(旧) V2(新)
类装饰器 @Observed @ObservedV2
属性追踪 @Track @Trace
组件装饰器 @Component @ComponentV2
内部状态 @State @Local
外部参数 @Prop/@Link @Param/@Event
计算属性 手动 get @Computed
变化监听 手动回调 @Monitor
初始化一次 @Once
全局存储 AppStorage AppStorageV2
持久化 PersistenceV2

这个对照表是开发者在 V1 和 V2 之间迁移时最重要的参考资料。

实际应用场景

场景一:表单编辑(细粒度更新)

假设一个用户设置页面有 20 个配置项。在 V1 中,每次修改任何一个配置项都会触发整个表单的重渲染。在 V2 中,通过 @Trace 标记每个配置项,只有修改的项对应的 UI 才更新,性能显著提升。

@ObservedV2
class UserSettings {
  @Trace enableNotifications: boolean = true;
  @Trace fontSize: number = 14;
  @Trace darkMode: boolean = false;
  @Trace language: string = 'zh-CN';
  // ... 其余 16 个配置项
}

场景二:购物车(@Computed 自动计算总价)

@Computed 在计算型场景中大放异彩。购物车的总价、折扣后价格、积分数等派生数据,都可以通过 @Computed 自动计算并缓存:

@ComponentV2
struct ShoppingCart {
  @Local items: CartItem[] = [];
  
  @Computed
  get totalPrice(): number {
    return this.items.reduce((sum, item) => sum + item.price * item.quantity, 0);
  }
  
  @Computed
  get discountPrice(): number {
    return this.totalPrice > 100 ? this.totalPrice * 0.9 : this.totalPrice;
  }
}

只要购物车商品不变,多次访问 totalPrice 只会计算一次。添加或删除商品时,两个计算属性自动重新计算。

场景三:实时搜索(@Monitor 防抖)

搜索框输入 → @Monitor 监听 → 自动触发搜索请求(带防抖):

@ComponentV2
struct SearchBox {
  @Local keyword: string = '';
  @Local results: SearchResult[] = [];
  private timer: number = -1;
  
  @Monitor('keyword')
  onKeywordChange(): void {
    clearTimeout(this.timer);
    this.timer = setTimeout(() => {
      this.search(this.keyword);
    }, 300);  // 300ms 防抖
  }
  
  search(keyword: string): void {
    // 调用搜索 API
  }
}

场景四:跨页面状态共享(AppStorageV2)

用户登录后,需要在多个页面共享用户信息和登录状态。使用 AppStorageV2

@ObservedV2
class AppState {
  @Trace isLoggedIn: boolean = false;
  @Trace userName: string = '';
  @Trace avatar: string = '';
}

// 在 App 初始化时注册
AppStorageV2.setOrCreate('app_state', new AppState());

// 在任何 @ComponentV2 中连接
@Local appState: AppState = AppStorageV2.connect(AppState, 'app_state')!;

一个组件修改 appState.isLoggedIn,所有连接了该状态的组件都会自动更新。

迁移策略建议

对于现有项目,从 V1 迁移到 V2 是一个渐进的过程。以下是一些策略建议:

  1. 新页面直接用 V2:对于新开发的功能页面,建议直接使用 @ComponentV2 + @ObservedV2 + @Trace
  2. 老页面逐模块迁移:对于复杂的 V1 页面,可以先将数据模型类迁移到 @ObservedV2(类装饰器变更不影响组件层),然后再逐个子组件迁移到 @ComponentV2
  3. 注意兼容性边界:V1 @Component 中不能使用 @ObservedV2 对象作为 @State 类型。在完全迁移前,V1 组件与 V2 组件需要通过事件回调进行通信,而不是通过 @Param 绑定。
  4. 优先迁移计算密集型场景:如果页面中有大量派生计算(getter 函数),优先迁移到 V2 以利用 @Computed 的缓存机制。
  5. 利用 @Monitor 解耦副作用:将 V1 中散落在各处的 aboutToUpdate 监听逻辑,逐步迁移到独立的 @Monitor 方法中,使代码更加模块化。

总结

本文通过构建一个"响应式档案编辑器",深入讲解了 HarmonyOS V2 状态管理系统的核心概念和 API:

  1. @ObservedV2 + @Trace:类级观察 + 属性级追踪,实现细粒度的依赖收集和更新通知。直接修改属性即可触发 UI 更新,不再需要替换整个对象引用。
  2. @ComponentV2:新一代组件模型,内置依赖追踪引擎,只有真正依赖了变化数据的组件才会重渲染。
  3. @Local / @Param / @Event:清晰的组件通信模型——@Local 管理内部状态,@Param 接收外部输入,@Event 向上传递事件。替代了 V1 中概念重叠的 @State/@Prop/@Link
  4. @Computed:声明式计算属性,自动缓存和依赖追踪。派生数据的计算逻辑与使用位置完全分离,代码更清晰。
  5. @Monitor:声明式状态监听,将"变化时做什么"从业务逻辑中分离出来。支持多属性监听和精确的路径表达式。
  6. AppStorageV2 + PersistenceV2:全局状态管理和持久化的新方案,支持复杂类型的自动序列化。

V2 状态管理系统是 HarmonyOS NEXT 最重要的架构升级之一。它借鉴了主流前端框架(如 Vue 3 的响应式系统、MobX 的细粒度追踪)的优秀设计,同时融入了 ArkUI 的声明式 UI 范式。对于那些正在或即将使用 HarmonyOS 进行大型应用开发的团队来说,掌握 V2 状态管理是提升代码质量和开发效率的关键一步。


Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐