4  第3章 高级状态管理

HarmonyOS应用开发者高级认证教程

Author

HarmonyOS技术专家

5 第3章 高级状态管理

5.1 学习目标

完成本章学习后,你将能够:

  • 深入理解状态管理V2的设计动机和使用方法
  • 掌握AppStorage、LocalStorage、PersistentStorage等全局状态管理方案
  • 熟练运用@State/@Prop/@Link/@Provide/@Consume等状态装饰器
  • 理解响应式数据流的底层原理(数据劫持、依赖收集、触发更新)
  • 设计合理的状态管理架构,实现状态分层和持久化

5.2 3.1 状态管理V2

5.2.1 3.1.1 V2状态管理的设计动机

HarmonyOS状态管理V2是对V1版本的重大升级,解决了V1中的多个痛点:

V1存在的问题:

// V1的问题1:@Observed只能观察第一层属性
@Observed
class V1Model {
    name: string = ""
    address: Address = new Address()  // 嵌套对象需要额外@Observed
}

@Observed
class Address {
    city: string = ""
    street: string = ""
}

// V1中修改嵌套属性可能不会触发UI更新
// model.address.city = "北京"  // 可能不触发更新

// V1的问题2:@ObjectLink不能接收@State的简单类型
// @ObjectLink只能接收@Observed类的实例

// V1的问题3:深层嵌套观察需要大量装饰器
// V1的问题4:缺少细粒度的状态控制

V2的设计目标:

  1. 更精确的观察粒度:支持深层属性自动观察
  2. 更简洁的API:减少装饰器数量,降低学习成本
  3. 更好的性能:按需更新,减少不必要的重渲染
  4. 更强的类型安全:编译时检查更完善

5.2.2 3.1.2 @ObservedV2装饰器

// 1. @ObservedV2基本使用
import { ObservedV2, Trace, local, param } from '@kit.ArkUI'

// @ObservedV2标记的类,其属性变化会被自动追踪
@ObservedV2
class TaskModel {
    // @Trace标记需要被追踪的属性
    @Trace title: string = ""
    @Trace completed: boolean = false
    @Trace priority: number = 0
    @Trace tags: string[] = []
    @Trace createdAt: number = Date.now()

    constructor(title: string, priority: number = 0) {
        this.title = title
        this.priority = priority
    }

    toggleComplete(): void {
        this.completed = !this.completed
    }

    addTag(tag: string): void {
        this.tags.push(tag)
    }
}

// 2. 嵌套对象的自动观察
@ObservedV2
class Address {
    @Trace city: string = ""
    @Trace street: string = ""
    @Trace zipCode: string = ""

    constructor(city: string, street: string, zipCode: string) {
        this.city = city
        this.street = street
        this.zipCode = zipCode
    }
}

@ObservedV2
class UserProfile {
    @Trace name: string = ""
    @Trace age: number = 0
    @Trace address: Address = new Address("", "", "")
    @Trace hobbies: string[] = []

    // 深层属性变化也会触发UI更新
    updateCity(city: string): void {
        this.address.city = city  // 会自动触发UI更新
    }
}

// 3. 在组件中使用@ObservedV2
@Component
struct TaskItemComponent {
    // 使用@ObjectLinkV2接收@ObservedV2对象
    @ObjectLinkV2 task: TaskModel

    build() {
        Row() {
            Checkbox()
                .select(this.task.completed)
                .onChange((checked: boolean) => {
                    this.task.toggleComplete()
                })

            Column() {
                Text(this.task.title)
                    .fontSize(16)
                    .decoration({
                        type: this.task.completed
                            ? TextDecorationType.LineThrough
                            : TextDecorationType.None
                    })
                Text(`优先级: ${this.task.priority}`)
                    .fontSize(12)
                    .fontColor('#666666')
                if (this.task.tags.length > 0) {
                    Row() {
                        ForEach(this.task.tags, (tag: string) => {
                            Text(tag)
                                .fontSize(10)
                                .padding({ left: 6, right: 6, top: 2, bottom: 2 })
                                .backgroundColor('#E3F2FD')
                                .borderRadius(4)
                                .margin({ right: 4 })
                        }, (tag: string) => tag)
                    }
                    .margin({ top: 4 })
                }
            }
            .layoutWeight(1)
            .alignItems(HorizontalAlign.Start)
            .padding({ left: 12 })
        }
        .width('100%')
        .padding(16)
        .backgroundColor('#FFFFFF')
        .borderRadius(12)
        .margin({ bottom: 8 })
    }
}

// 4. 父组件管理任务列表
@Component
struct TaskListView {
    @State tasks: TaskModel[] = []
    @State newTaskTitle: string = ""

    aboutToAppear(): void {
        // 初始化任务数据
        this.tasks = [
            new TaskModel("完成项目报告", 1),
            new TaskModel("准备会议材料", 2),
            new TaskModel("代码审查", 1)
        ]
        this.tasks[0].addTag("工作")
        this.tasks[1].addTag("会议")
        this.tasks[2].addTag("开发")
    }

    build() {
        Column() {
            // 添加任务
            Row() {
                TextInput({ placeholder: "添加新任务..." })
                    .layoutWeight(1)
                    .onChange((value: string) => {
                        this.newTaskTitle = value
                    })
                Button("添加")
                    .onClick(() => {
                        if (this.newTaskTitle.length > 0) {
                            let newTask = new TaskModel(this.newTaskTitle)
                            this.tasks.push(newTask)
                            this.newTaskTitle = ""
                        }
                    })
            }
            .padding(16)

            // 任务列表
            List() {
                ForEach(this.tasks, (task: TaskModel) => {
                    ListItem() {
                        TaskItemComponent({ task: task })
                    }
                }, (task: TaskModel) => task.title + task.createdAt.toString())
            }
            .width('100%')
            .layoutWeight(1)

            // 统计信息
            Text(`总计: ${this.tasks.length} | 完成: ${this.getCompletedCount()}`)
                .fontSize(14)
                .fontColor('#999999')
                .padding(16)
        }
    }

    private getCompletedCount(): number {
        return this.tasks.filter((t: TaskModel) => t.completed).length
    }
}

5.2.3 3.1.3 @ObjectLinkV2使用

// 1. @ObjectLinkV2与@ObjectLink的区别
// @ObjectLinkV2:
//   - 配合@ObservedV2使用
//   - 支持更细粒度的属性观察
//   - 只追踪实际被UI使用的属性

// @ObjectLink:
//   - 配合@Observed使用
//   - 观察整个对象的变化
//   - 可能导致不必要的重渲染

// 2. @ObjectLinkV2的初始化方式
@Component
struct ChildComponent {
    // 方式1:通过@ObjectLinkV2接收父组件传递的对象
    @ObjectLinkV2 model: UserProfile

    build() {
        Column() {
            Text(`姓名: ${this.model.name}`)
            Text(`年龄: ${this.model.age}`)
            Text(`城市: ${this.model.address.city}`)

            Button("修改城市")
                .onClick(() => {
                    // 修改嵌套属性也会触发更新
                    this.model.address.city = "上海"
                })
        }
    }
}

// 3. 使用@Local和@Param装饰器
@Component
struct CounterComponent {
    // @Local: 组件内部本地状态
    @Local count: number = 0
    // @Param: 从父组件接收的参数(单向)
    @Param step: number = 1

    build() {
        Column({ space: 16 }) {
            Text(`计数: ${this.count}`)
                .fontSize(24)
            Row({ space: 12 }) {
                Button(`+${this.step}`)
                    .onClick(() => { this.count += this.step })
                Button(`-${this.step}`)
                    .onClick(() => { this.count -= this.step })
                Button("重置")
                    .onClick(() => { this.count = 0 })
            }
        }
    }
}

// 父组件使用
@Component
struct ParentComponent {
    @State stepValue: number = 5

    build() {
        Column({ space: 20 }) {
            CounterComponent({ step: this.stepValue })

            Row({ space: 12 }) {
                Button("步长=1")
                    .onClick(() => { this.stepValue = 1 })
                Button("步长=5")
                    .onClick(() => { this.stepValue = 5 })
                Button("步长=10")
                    .onClick(() => { this.stepValue = 10 })
            }
        }
    }
}

// 4. @ObservedV2中的计算属性
@ObservedV2
class CartModel {
    @Trace items: CartItem[] = []
    @Trace discountRate: number = 1.0  // 1.0表示无折扣

    addItem(item: CartItem): void {
        this.items.push(item)
    }

    removeItem(index: number): void {
        this.items.splice(index, 1)
    }

    // 计算属性 - 总价
    get totalPrice(): number {
        return this.items.reduce(
            (sum: number, item: CartItem) => sum + item.price * item.quantity,
            0
        ) * this.discountRate
    }

    // 计算属性 - 商品数量
    get itemCount(): number {
        return this.items.reduce(
            (sum: number, item: CartItem) => sum + item.quantity,
            0
        )
    }

    applyDiscount(rate: number): void {
        this.discountRate = rate
    }
}

class CartItem {
    name: string
    price: number
    quantity: number

    constructor(name: string, price: number, quantity: number) {
        this.name = name
        this.price = price
        this.quantity = quantity
    }
}

// 在组件中使用计算属性
@Component
struct CartView {
    @ObjectLinkV2 cart: CartModel

    build() {
        Column() {
            List() {
                ForEach(this.cart.items, (item: CartItem, index: number) => {
                    ListItem() {
                        Row() {
                            Text(item.name).layoutWeight(1)
                            Text(${item.price} x ${item.quantity}`)
                            Button("删除")
                                .onClick(() => {
                                    this.cart.removeItem(index)
                                })
                        }
                        .padding(12)
                    }
                }, (item: CartItem) => item.name)
            }
            .layoutWeight(1)

            // 底部结算栏
            Column() {
                Text(`商品数量: ${this.cart.itemCount}`)
                Text(`总计: ¥${this.cart.totalPrice.toFixed(2)}`)
                    .fontSize(24)
                    .fontWeight(FontWeight.Bold)
                    .fontColor('#FF4444')
                Button("结算")
                    .width('100%')
                    .margin({ top: 12 })
            }
            .padding(16)
            .backgroundColor('#F5F5F5')
        }
    }
}

5.2.4 3.1.4 V1与V2的对比与迁移

// V1到V2的迁移对照表

/*
┌──────────────────┬──────────────────────┬──────────────────────┐
│     功能          │      V1              │      V2              │
├──────────────────┼──────────────────────┼──────────────────────┤
│ 组件内部状态      │ @State               │ @Local               │
│ 父传子(单向)      │ @Prop                │ @Param               │
│ 父传子(双向)      │ @Link                │ @Event               │
│ 观察对象          │ @Observed            │ @ObservedV2          │
│ 接收观察对象      │ @ObjectLink          │ @ObjectLinkV2        │
│ 跨层级传递        │ @Provide/@Consume    │ @Provider/@Consumer  │
│ 全局状态          │ AppStorage           │ AppStorage(保持)      │
│ 页面级状态        │ LocalStorage         │ LocalStorage(保持)    │
│ 持久化            │ PersistentStorage    │ PersistentStorage    │
│ 环境状态          │ Environment          │ Environment          │
│ 状态监听          │ @Watch               │ @Monitor             │
└──────────────────┴──────────────────────┴──────────────────────┘
*/

// V1写法
@Observed
class V1UserModel {
    name: string = ""
    age: number = 0
}

@Component
struct V1ChildComponent {
    @ObjectLink user: V1UserModel

    build() {
        Text(`${this.user.name}, ${this.user.age}岁`)
    }
}

// V2写法(迁移后)
@ObservedV2
class V2UserModel {
    @Trace name: string = ""
    @Trace age: number = 0
}

@Component
struct V2ChildComponent {
    @ObjectLinkV2 user: V2UserModel

    build() {
        Text(`${this.user.name}, ${this.user.age}岁`)
    }
}

// 迁移注意事项:
// 1. @Observed -> @ObservedV2,属性需要加@Trace
// 2. @ObjectLink -> @ObjectLinkV2
// 3. @State -> @Local(组件内部状态)
// 4. @Prop -> @Param(单向传递)
// 5. @Link -> @Event(双向绑定)
// 6. V1和V2可以混合使用,但建议逐步迁移

5.3 3.2 全局状态管理方案

5.3.1 3.2.1 AppStorage深入

// AppStorage是应用级别的全局状态存储
// 所有页面和组件都可以访问

// 1. AppStorage基本操作
@Component
struct AppStorageExample {
    // 通过@StorageLink双向绑定AppStorage
    @StorageLink('userName'): string = ''
    // 通过@StorageProp单向读取AppStorage
    @StorageProp('appVersion'): appVersion: string = '1.0.0'
    // 通过@StorageLink绑定复杂对象
    @StorageLink('userSettings'): settings: UserSettings = new UserSettings()

    aboutToAppear(): void {
        // 初始化AppStorage
        if (!AppStorage.has('userName')) {
            AppStorage.setOrCreate('userName', '默认用户')
        }
        if (!AppStorage.has('appVersion')) {
            AppStorage.setOrCreate('appVersion', '1.0.0')
        }
        if (!AppStorage.has('userSettings')) {
            AppStorage.setOrCreate('userSettings', new UserSettings())
        }
    }

    build() {
        Column({ space: 16 }) {
            // 双向绑定 - 修改会同步到AppStorage
            TextInput({ text: this.userName, placeholder: "用户名" })
                .onChange((value: string) => {
                    this.userName = value
                })

            // 单向读取
            Text(`版本: ${this.appVersion}`)
                .fontSize(14)
                .fontColor('#666666')

            // 修改AppStorage中的值
            Button("更新用户名")
                .onClick(() => {
                    this.userName = "新用户名"
                    // 等价于 AppStorage.set('userName', '新用户名')
                })

            // 监听AppStorage变化
            Button("读取设置")
                .onClick(() => {
                    let settings: UserSettings =
                        AppStorage.get('userSettings') as UserSettings
                    console.log(`主题: ${settings.theme}`)
                    console.log(`字体大小: ${settings.fontSize}`)
                })
        }
        .padding(24)
    }
}

// 2. AppStorage的高级用法
class UserSettings {
    theme: string = "light"
    fontSize: number = 14
    language: string = "zh-CN"
    notifications: boolean = true
}

// 全局状态管理器
class GlobalStateManager {
    // 初始化所有全局状态
    static initialize(): void {
        // 用户信息
        AppStorage.setOrCreate('currentUser', null)
        AppStorage.setOrCreate('isAuthenticated', false)

        // 应用设置
        let defaultSettings = new UserSettings()
        AppStorage.setOrCreate('userSettings', defaultSettings)

        // 网络状态
        AppStorage.setOrCreate('isOnline', true)
        AppStorage.setOrCreate('networkType', 'wifi')

        // 应用级UI状态
        AppStorage.setOrCreate('isLoading', false)
        AppStorage.setOrCreate('errorMessage', '')
    }

    // 用户登录
    static login(user: Object): void {
        AppStorage.set('currentUser', user)
        AppStorage.set('isAuthenticated', true)
    }

    // 用户登出
    static logout(): void {
        AppStorage.set('currentUser', null)
        AppStorage.set('isAuthenticated', false)
    }

    // 更新网络状态
    static updateNetworkStatus(online: boolean, type: string): void {
        AppStorage.set('isOnline', online)
        AppStorage.set('networkType', type)
    }

    // 显示全局加载
    static showLoading(): void {
        AppStorage.set('isLoading', true)
    }

    static hideLoading(): void {
        AppStorage.set('isLoading', false)
    }
}

// 3. 在EntryAbility中初始化全局状态
export default class EntryAbility extends UIAbility {
    onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
        // 初始化全局状态
        GlobalStateManager.initialize()
    }

    onWindowStageCreate(windowStage: window.WindowStage): void {
        windowStage.loadContent('pages/Index')
    }
}

5.3.2 3.2.2 LocalStorage与PersistentStorage

// 1. LocalStorage - 页面级别的状态存储
// 每个UIAbility页面有独立的LocalStorage

// 在UIAbility中创建LocalStorage
export default class DetailAbility extends UIAbility {
    // 创建页面级LocalStorage
    private pageStorage: LocalStorage = new LocalStorage()

    onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
        // 初始化页面级状态
        this.pageStorage.setOrCreate('pageTitle', '详情页')
        this.pageStorage.setOrCreate('itemId', 0)

        // 从Want中获取参数存入LocalStorage
        if (want.parameters) {
            let itemId: number = want.parameters['itemId'] as number ?? 0
            this.pageStorage.set('itemId', itemId)
        }
    }

    onWindowStageCreate(windowStage: window.WindowStage): void {
        // 将LocalStorage与窗口关联
        windowStage.loadContent('pages/Detail', (err) => {
            if (err.code) return
        })
    }
}

// 在组件中使用LocalStorage
@Entry(new LocalStorage())
@Component
struct DetailPage {
    @LocalStorageLink('pageTitle') pageTitle: string = ''
    @LocalStorageLink('itemId') itemId: number = 0
    @LocalStorageProp('pageTitle') title: string = ''

    build() {
        Column() {
            Text(this.pageTitle)
                .fontSize(24)
                .fontWeight(FontWeight.Bold)
            Text(`商品ID: ${this.itemId}`)
                .fontSize(16)
        }
    }
}

// 2. PersistentStorage - 持久化存储
// 数据会在应用重启后保留

@Component
struct PersistentStorageExample {
    // 通过@StorageLink自动持久化
    @StorageLink('theme'): string = 'light'
    @StorageLink('fontSize'): number = 14
    @StorageLink('lastLoginTime'): number = 0

    aboutToAppear(): void {
        // 配置PersistentStorage
        // 通常在EntryAbility的onCreate中配置
        // PersistentStorage.persistProp('theme', 'light')
        // PersistentStorage.persistProp('fontSize', 14)
        // PersistentStorage.persistProp('lastLoginTime', 0)
    }

    build() {
        Column({ space: 20 }) {
            // 主题选择
            Text("主题设置")
                .fontSize(18)
                .fontWeight(FontWeight.Medium)

            Row({ space: 12 }) {
                Button("浅色")
                    .backgroundColor(this.theme === 'light' ? '#2196F3' : '#E0E0E0')
                    .onClick(() => { this.theme = 'light' })
                Button("深色")
                    .backgroundColor(this.theme === 'dark' ? '#2196F3' : '#E0E0E0')
                    .onClick(() => { this.theme = 'dark' })
            }

            // 字体大小
            Text(`字体大小: ${this.fontSize}`)
            Slider({
                value: this.fontSize,
                min: 12,
                max: 24,
                step: 1
            })
                .onChange((value: number) => {
                    this.fontSize = value
                })

            // 上次登录时间
            Text(`上次登录: ${this.formatTime(this.lastLoginTime)}`)
                .fontSize(12)
                .fontColor('#999999')

            Button("记录登录时间")
                .onClick(() => {
                    this.lastLoginTime = Date.now()
                })
        }
        .padding(24)
    }

    private formatTime(timestamp: number): string {
        if (timestamp === 0) return "从未登录"
        let date = new Date(timestamp)
        return `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')} ${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`
    }
}

// 3. 在EntryAbility中配置PersistentStorage
export default class EntryAbility extends UIAbility {
    onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
        // 配置需要持久化的属性
        PersistentStorage.persistProp('theme', 'light')
        PersistentStorage.persistProp('fontSize', 14)
        PersistentStorage.persistProp('lastLoginTime', 0)
        PersistentStorage.persistProp('userName', '')
        PersistentStorage.persistProp('isFirstLaunch', true)
    }

    onWindowStageCreate(windowStage: window.WindowStage): void {
        windowStage.loadContent('pages/Index')
    }
}

5.3.3 3.2.3 Environment环境变量管理

// Environment用于管理设备环境相关的状态

@Component
struct EnvironmentExample {
    // 通过@StorageLink读取环境变量
    @StorageLink('systemLanguage') systemLanguage: string = ''
    @StorageLink('colorMode') colorMode: number = 0

    aboutToAppear(): void {
        // 环境变量由系统自动管理
        // 可用的环境变量包括:
        // - colorMode: 颜色模式(0=浅色,1=深色)
        // - systemLanguage: 系统语言
        // - fontScale: 字体缩放比例
    }

    build() {
        Column({ space: 16 }) {
            // 根据颜色模式切换样式
            Text("环境感知组件")
                .fontSize(24)
                .fontColor(this.colorMode === 1 ? '#FFFFFF' : '#000000')

            Text(`系统语言: ${this.systemLanguage}`)
                .fontSize(16)

            Text(`颜色模式: ${this.colorMode === 1 ? '深色' : '浅色'}`)
                .fontSize(16)

            // 根据环境调整UI
            Column() {
                Text("自适应内容")
                    .fontSize(16)
                    .fontColor(this.colorMode === 1 ? '#CCCCCC' : '#333333')
            }
            .width('100%')
            .padding(16)
            .backgroundColor(this.colorMode === 1 ? '#1E1E1E' : '#FFFFFF')
            .borderRadius(12)
        }
        .width('100%')
        .height('100%')
        .padding(24)
        .backgroundColor(this.colorMode === 1 ? '#121212' : '#F5F5F5')
    }
}

// 自定义环境配置管理
class EnvironmentConfig {
    // 根据设备类型返回不同配置
    static getConfig(): DeviceConfig {
        let config: DeviceConfig = {
            isPhone: true,
            isTablet: false,
            screenDensity: 2,
            maxColumns: 1
        }

        // 实际项目中通过deviceInfo获取设备信息
        // import { deviceInfo } from '@kit.BasicServicesKit'
        // config.isTablet = deviceInfo.deviceType === 'tablet'

        if (config.isTablet) {
            config.maxColumns = 3
            config.screenDensity = 2
        }

        return config
    }
}

interface DeviceConfig {
    isPhone: boolean
    isTablet: boolean
    screenDensity: number
    maxColumns: number
}

5.3.4 3.2.4 全局状态的最佳实践

// 全局状态管理最佳实践

// 1. 状态分类与存储位置选择
/*
┌────────────────────┬───────────────────┬──────────────────────┐
│     状态类型        │    存储位置        │      示例             │
├────────────────────┼───────────────────┼──────────────────────┤
│ 组件内部UI状态      │ @Local/@State     │ 展开/折叠状态         │
│ 父子组件共享状态    │ @Param/@Event     │ 表单数据              │
│ 跨组件共享状态      │ @Provide/@Consume │ 主题配置              │
│ 应用级运行时状态    │ AppStorage        │ 用户登录状态          │
│ 页面级状态          │ LocalStorage      │ 页面导航参数          │
│ 需要持久化的状态    │ PersistentStorage │ 用户偏好设置          │
│ 环境变量            │ Environment       │ 颜色模式、语言        │
└────────────────────┴───────────────────┴──────────────────────┘
*/

// 2. 全局状态管理器设计模式
@ObservedV2
class AuthStore {
    @Trace currentUser: UserInfo | null = null
    @Trace isAuthenticated: boolean = false
    @Trace token: string = ""

    async login(username: string, password: string): Promise<boolean> {
        try {
            // 模拟API调用
            let response: Object = await this.callLoginApi(username, password)
            let record = response as Record<string, Object>

            this.currentUser = new UserInfo(
                record['id'] as number,
                record['name'] as string,
                record['email'] as string
            )
            this.token = record['token'] as string
            this.isAuthenticated = true

            // 同步到AppStorage
            AppStorage.set('currentUser', this.currentUser)
            AppStorage.set('isAuthenticated', true)
            AppStorage.set('token', this.token)

            return true
        } catch (error) {
            console.error("登录失败:", error)
            return false
        }
    }

    logout(): void {
        this.currentUser = null
        this.token = ""
        this.isAuthenticated = false

        AppStorage.set('currentUser', null)
        AppStorage.set('isAuthenticated', false)
        AppStorage.set('token', '')
    }

    private async callLoginApi(
        username: string,
        password: string
    ): Promise<Object> {
        return new Promise<Object>((resolve) => {
            setTimeout(() => {
                resolve({
                    id: 1,
                    name: username,
                    email: `${username}@example.com`,
                    token: "mock_token_12345"
                })
            }, 1000)
        })
    }
}

class UserInfo {
    id: number
    name: string
    email: string

    constructor(id: number, name: string, email: string) {
        this.id = id
        this.name = name
        this.email = email
    }
}

// 3. 全局状态单例管理
class StoreRegistry {
    private static authStore: AuthStore | null = null
    private static cartStore: CartStore | null = null

    static getAuth(): AuthStore {
        if (!StoreRegistry.authStore) {
            StoreRegistry.authStore = new AuthStore()
        }
        return StoreRegistry.authStore
    }

    static getCart(): CartStore {
        if (!StoreRegistry.cartStore) {
            StoreRegistry.cartStore = new CartStore()
        }
        return StoreRegistry.cartStore
    }
}

@ObservedV2
class CartStore {
    @Trace items: CartItemV2[] = []

    get totalAmount(): number {
        return this.items.reduce(
            (sum: number, item: CartItemV2) => sum + item.totalPrice,
            0
        )
    }

    addItem(product: ProductInfo, quantity: number = 1): void {
        let existing: CartItemV2[] = this.items.filter(
            (item: CartItemV2) => item.productId === product.id
        )
        if (existing.length > 0) {
            existing[0].quantity += quantity
        } else {
            this.items.push(new CartItemV2(product, quantity))
        }
    }

    removeItem(productId: number): void {
        this.items = this.items.filter(
            (item: CartItemV2) => item.productId !== productId
        )
    }

    clear(): void {
        this.items = []
    }
}

@ObservedV2
class CartItemV2 {
    @Trace productId: number
    @Trace productName: string
    @Trace price: number
    @Trace quantity: number

    constructor(product: ProductInfo, quantity: number) {
        this.productId = product.id
        this.productName = product.name
        this.price = product.price
        this.quantity = quantity
    }

    get totalPrice(): number {
        return this.price * this.quantity
    }
}

class ProductInfo {
    id: number
    name: string
    price: number

    constructor(id: number, name: string, price: number) {
        this.id = id
        this.name = name
        this.price = price
    }
}

5.4 3.3 组件间状态共享

5.4.1 3.3.1 @State/@Prop/@Link深入

// 1. @State - 组件内部状态
@Component
struct StateExample {
    @State count: number = 0
    @State message: string = "Hello"
    @State isVisible: boolean = true
    @State items: string[] = ["苹果", "香蕉", "橙子"]

    build() {
        Column({ space: 12 }) {
            Text(`计数: ${this.count}`)
            Button("+1").onClick(() => { this.count++ })

            Text(this.message)
            Button("修改消息").onClick(() => {
                this.message = "消息已更新 " + this.count
            })

            if (this.isVisible) {
                Text("可见内容")
            }
            Button("切换可见性").onClick(() => {
                this.isVisible = !this.isVisible
            })

            // 数组状态
            List() {
                ForEach(this.items, (item: string) => {
                    ListItem() {
                        Text(item)
                    }
                }, (item: string) => item)
            }
        }
    }
}

// 2. @Prop - 父到子的单向数据流
@Component
struct ChildDisplay {
    // @Prop: 从父组件接收,子组件修改不会影响父组件
    @Prop title: string = ""
    @Prop count: number = 0

    @State localCount: number = 0

    build() {
        Column({ space: 8 }) {
            Text(`标题: ${this.title}`)
                .fontSize(18)
            Text(`来自父组件: ${this.count}`)
                .fontSize(16)
            Text(`本地计数: ${this.localCount}`)
                .fontSize(16)
            Button("本地+1")
                .onClick(() => {
                    this.localCount++
                    // 修改@Prop值不会影响父组件
                    this.count++  // 只修改本地副本
                })
        }
        .padding(16)
        .backgroundColor('#F0F0F0')
        .borderRadius(8)
    }
}

@Component
struct ParentWithProp {
    @State parentCount: number = 0

    build() {
        Column({ space: 16 }) {
            Text(`父组件计数: ${this.parentCount}`)
            Button("父+1").onClick(() => { this.parentCount++ })

            // 传递给子组件
            ChildDisplay({
                title: "子组件示例",
                count: this.parentCount
            })
        }
        .padding(24)
    }
}

// 3. @Link - 父到子的双向数据绑定
@Component
struct ChildEditor {
    // @Link: 与父组件双向绑定
    @Link value: number
    @Link text: string

    build() {
        Column({ space: 12 }) {
            Text(`子组件值: ${this.value}`)
                .fontSize(18)

            Button("子+1").onClick(() => {
                this.value++  // 修改会同步到父组件
            })

            Button("子-1").onClick(() => {
                this.value--  // 修改会同步到父组件
            })

            TextInput({ text: this.text })
                .onChange((val: string) => {
                    this.text = val  // 文本变化也会同步
                })
        }
        .padding(16)
        .backgroundColor('#E8F5E9')
        .borderRadius(8)
    }
}

@Component
struct ParentWithLink {
    @State parentValue: number = 10
    @State parentText: string = "初始文本"

    build() {
        Column({ space: 16 }) {
            Text(`父组件值: ${this.parentValue}`)
                .fontSize(20)
            Text(`父组件文本: ${this.parentText}`)
                .fontSize(16)

            // 使用$传递引用
            ChildEditor({
                value: $parentValue,
                text: $parentText
            })
        }
        .padding(24)
    }
}

5.4.2 3.3.2 @Provide/@Consume跨层级通信

// @Provide/@Consume允许跨越多层组件直接传递状态

// 1. 基本使用
@Component
struct ThemeProvider {
    @Provide('theme') themeColor: string = '#2196F3'
    @Provide('fontSize') baseFontSize: number = 14

    build() {
        Column() {
            Text("主题提供者")
                .fontSize(20)
                .fontColor(this.themeColor)

            // 中间可能有多层组件嵌套
            MiddleComponent()

            Row({ space: 12 }) {
                Button("蓝色主题")
                    .onClick(() => { this.themeColor = '#2196F3' })
                Button("绿色主题")
                    .onClick(() => { this.themeColor = '#4CAF50' })
                Button("红色主题")
                    .onClick(() => { this.themeColor = '#F44336' })
            }
        }
        .padding(24)
    }
}

@Component
struct MiddleComponent {
    build() {
        Column() {
            Text("中间组件(不需要传递状态)")
                .fontSize(14)
                .fontColor('#666666')

            // 直接嵌套深层组件,不需要手动传递theme
            DeepChildComponent()
        }
        .padding(16)
        .margin(8)
    }
}

@Component
struct DeepChildComponent {
    // @Consume自动从祖先组件获取@Provide的值
    @Consume('theme') themeColor: string
    @Consume('fontSize') baseFontSize: number

    build() {
        Column() {
            Text("深层子组件")
                .fontSize(this.baseFontSize + 4)
                .fontColor(this.themeColor)
            Text("自动获取了祖先组件的主题色")
                .fontSize(this.baseFontSize)

            Button("使用主题色")
                .backgroundColor(this.themeColor)
        }
        .padding(16)
        .margin(8)
        .border({ width: 2, color: this.themeColor })
        .borderRadius(8)
    }
}

// 2. 复杂场景:全局配置注入
@ObservedV2
class AppConfig {
    @Trace language: string = "zh-CN"
    @Trace theme: string = "light"
    @Trace region: string = "CN"

    get isDarkMode(): boolean {
        return this.theme === "dark"
    }

    get isChinese(): boolean {
        return this.language.startsWith("zh")
    }
}

@Component
struct ConfigProvider {
    @Provide('appConfig') config: AppConfig = new AppConfig()

    build() {
        Column() {
            // 配置面板
            Row({ space: 12 }) {
                Button("中文")
                    .onClick(() => { this.config.language = "zh-CN" })
                Button("English")
                    .onClick(() => { this.config.language = "en-US" })
                Button("深色")
                    .onClick(() => { this.config.theme = "dark" })
                Button("浅色")
                    .onClick(() => { this.config.theme = "light" })
            }
            .padding(16)

            // 子组件自动获取配置
            ConfigConsumer()
        }
    }
}

@Component
struct ConfigConsumer {
    @Consume('appConfig') config: AppConfig

    build() {
        Column({ space: 8 }) {
            Text(this.config.isChinese ? "当前语言:中文" : "Current: English")
            Text(this.config.isDarkMode ? "深色模式" : "浅色模式")
        }
        .padding(16)
        .backgroundColor(this.config.isDarkMode ? '#1E1E1E' : '#FFFFFF')
    }
}

// 3. @Provide/@Consume与@StorageLink的配合使用
@Component
struct GlobalThemeProvider {
    @Provide('globalTheme') globalTheme: string = 'light'
    @StorageLink('theme') storedTheme: string = 'light'

    aboutToAppear(): void {
        this.globalTheme = this.storedTheme
    }

    build() {
        Column() {
            Text(`全局主题: ${this.globalTheme}`)
            Button("切换主题")
                .onClick(() => {
                    let newTheme: string =
                        this.globalTheme === 'light' ? 'dark' : 'light'
                    this.globalTheme = newTheme
                    this.storedTheme = newTheme  // 同步到持久化存储
                })
        }
    }
}

5.4.3 3.3.3 @Watch状态监听

// 1. @Watch基本使用
@Component
struct WatchExample {
    @State @Watch('onCountChange') count: number = 0
    @State @Watch('onTextChange') text: string = ""
    @State log: string[] = []

    // 当count变化时触发
    onCountChange(): void {
        this.log.push(`count变为: ${this.count}`)
        if (this.log.length > 5) {
            this.log.shift()
        }
    }

    // 当text变化时触发
    onTextChange(): void {
        this.log.push(`text变为: "${this.text}" (长度: ${this.text.length})`)
        if (this.log.length > 5) {
            this.log.shift()
        }
    }

    build() {
        Column({ space: 16 }) {
            Text(`计数: ${this.count}`)
                .fontSize(24)

            Row({ space: 12 }) {
                Button("+1").onClick(() => { this.count++ })
                Button("-1").onClick(() => { this.count-- })
                Button("x2").onClick(() => { this.count *= 2 })
            }

            TextInput({ placeholder: "输入文本..." })
                .onChange((value: string) => { this.text = value })

            // 显示变化日志
            Column() {
                Text("变化日志:")
                    .fontSize(14)
                    .fontWeight(FontWeight.Medium)
                ForEach(this.log, (entry: string) => {
                    Text(entry)
                        .fontSize(12)
                        .fontColor('#666666')
                }, (entry: string) => entry)
            }
            .alignItems(HorizontalAlign.Start)
            .padding(12)
            .backgroundColor('#F5F5F5')
            .borderRadius(8)
        }
        .padding(24)
    }
}

// 2. @Watch实现表单验证
@Component
struct FormValidationExample {
    @State @Watch('validateEmail') email: string = ""
    @State @Watch('validatePassword') password: string = ""
    @State @Watch('validateConfirm') confirmPassword: string = ""

    @State emailError: string = ""
    @State passwordError: string = ""
    @State confirmError: string = ""
    @State isFormValid: boolean = false

    validateEmail(): void {
        if (this.email.length === 0) {
            this.emailError = "邮箱不能为空"
        } else if (!this.email.includes('@')) {
            this.emailError = "请输入有效的邮箱地址"
        } else {
            this.emailError = ""
        }
        this.checkFormValidity()
    }

    validatePassword(): void {
        if (this.password.length === 0) {
            this.passwordError = "密码不能为空"
        } else if (this.password.length < 8) {
            this.passwordError = "密码至少8个字符"
        } else if (!/[A-Z]/.test(this.password)) {
            this.passwordError = "密码需要包含大写字母"
        } else {
            this.passwordError = ""
        }
        this.checkFormValidity()
        this.validateConfirm()
    }

    validateConfirm(): void {
        if (this.confirmPassword !== this.password) {
            this.confirmError = "两次密码输入不一致"
        } else {
            this.confirmError = ""
        }
        this.checkFormValidity()
    }

    checkFormValidity(): void {
        this.isFormValid =
            this.emailError.length === 0 &&
            this.passwordError.length === 0 &&
            this.confirmError.length === 0 &&
            this.email.length > 0 &&
            this.password.length > 0 &&
            this.confirmPassword.length > 0
    }

    build() {
        Column({ space: 16 }) {
            Text("用户注册")
                .fontSize(24)
                .fontWeight(FontWeight.Bold)

            // 邮箱
            Column() {
                TextInput({ placeholder: "邮箱地址" })
                    .onChange((value: string) => { this.email = value })
                if (this.emailError.length > 0) {
                    Text(this.emailError)
                        .fontSize(12)
                        .fontColor('#F44336')
                }
            }
            .alignItems(HorizontalAlign.Start)

            // 密码
            Column() {
                TextInput({ placeholder: "密码" })
                    .type(InputType.Password)
                    .onChange((value: string) => { this.password = value })
                if (this.passwordError.length > 0) {
                    Text(this.passwordError)
                        .fontSize(12)
                        .fontColor('#F44336')
                }
            }
            .alignItems(HorizontalAlign.Start)

            // 确认密码
            Column() {
                TextInput({ placeholder: "确认密码" })
                    .type(InputType.Password)
                    .onChange((value: string) => { this.confirmPassword = value })
                if (this.confirmError.length > 0) {
                    Text(this.confirmError)
                        .fontSize(12)
                        .fontColor('#F44336')
                }
            }
            .alignItems(HorizontalAlign.Start)

            Button("注册")
                .enabled(this.isFormValid)
                .width('100%')
                .onClick(() => {
                    console.log("注册成功")
                })
        }
        .padding(24)
    }
}

// 3. @Watch与@Monitor(V2)的对比
// @Watch: V1版本,监听单个状态变化
// @Monitor: V2版本,可以监听多个状态变化

@Component
struct MonitorExample {
    @Local firstName: string = ""
    @Local lastName: string = ""
    @State fullName: string = ""

    // V2的@Monitor可以监听多个属性
    // @Monitor(['firstName', 'lastName'])
    onNameChange(): void {
        this.fullName = `${this.firstName} ${this.lastName}`
    }

    build() {
        Column({ space: 12 }) {
            TextInput({ placeholder: "名" })
                .onChange((value: string) => { this.firstName = value })
            TextInput({ placeholder: "姓" })
                .onChange((value: string) => { this.lastName = value })
            Text(`全名: ${this.fullName}`)
                .fontSize(18)
        }
        .padding(24)
    }
}

5.4.4 3.3.4 状态管理的性能影响

// 1. 避免不必要的重渲染
// 错误示例:在build()中创建大量不必要的状态依赖
@Component
struct BadPerformanceExample {
    @State allData: string[] = []
    @State selectedIndex: number = -1

    build() {
        Column() {
            // 问题:每次selectedIndex变化,整个列表都会重渲染
            ForEach(this.allData, (item: string, index: number) => {
                ListItem() {
                    Text(item)
                        .backgroundColor(
                            index === this.selectedIndex ? '#2196F3' : '#FFFFFF'
                        )
                }
            }, (item: string) => item)
        }
    }
}

// 优化方案:将选中状态隔离到子组件
@Component
struct GoodPerformanceExample {
    @State allData: string[] = []
    @State selectedIndex: number = -1

    build() {
        Column() {
            ForEach(this.allData, (item: string, index: number) => {
                ListItem() {
                    // 选中状态隔离在子组件中
                    IsolatedItem({
                        text: item,
                        isSelected: index === this.selectedIndex,
                        onSelect: () => { this.selectedIndex = index }
                    })
                }
            }, (item: string) => item)
        }
    }
}

@Component
struct IsolatedItem {
    text: string = ""
    isSelected: boolean = false
    onSelect: () => void = () => {}

    build() {
        Text(this.text)
            .backgroundColor(this.isSelected ? '#2196F3' : '#FFFFFF')
            .onClick(() => { this.onSelect() })
    }
}

// 2. 使用LazyForEach优化长列表
@Component
struct LazyListExample {
    private dataSource: MyDataSource = new MyDataSource()

    aboutToAppear(): void {
        // 初始化大量数据
        for (let i: number = 0; i < 10000; i++) {
            this.dataSource.addData(`项目 ${i + 1}`)
        }
    }

    build() {
        List() {
            LazyForEach(this.dataSource, (item: string) => {
                ListItem() {
                    Text(item)
                        .fontSize(16)
                        .padding(16)
                }
            }, (item: string) => item)
        }
        .width('100%')
        .height('100%')
    }
}

// LazyForEach数据源实现
class MyDataSource implements IDataSource {
    private data: string[] = []
    private listeners: DataChangeListener[] = []

    totalCount(): number {
        return this.data.length
    }

    getData(index: number): string {
        return this.data[index]
    }

    addData(item: string): void {
        this.data.push(item)
        // 通知LazyForEach数据变化
        for (let listener of this.listeners) {
            listener.onDataAdded(this.data.length - 1)
        }
    }

    registerDataChangeListener(
        listener: DataChangeListener
    ): void {
        this.listeners.push(listener)
    }

    unregisterDataChangeListener(
        listener: DataChangeListener
    ): void {
        let index: number = this.listeners.indexOf(listener)
        if (index >= 0) {
            this.listeners.splice(index, 1)
        }
    }
}

// 3. 状态更新批处理
// 在一次事件处理中多次修改状态,框架会自动批处理
@Component
struct BatchUpdateExample {
    @State a: number = 0
    @State b: number = 0
    @State c: number = 0

    build() {
        Column({ space: 12 }) {
            Text(`A: ${this.a}, B: ${this.b}, C: ${this.c}`)

            Button("同时更新")
                .onClick(() => {
                    // 这些状态更新会被批处理
                    // 只会触发一次UI重渲染
                    this.a++
                    this.b += 2
                    this.c += 3
                })
        }
    }
}

5.5 3.4 响应式数据流

5.5.1 3.4.1 数据劫持与代理模式

// HarmonyOS状态管理的底层原理

// 1. 数据劫持 - Object.defineProperty方式(V1原理)
function createReactiveV1<T extends Object>(obj: T): T {
    let reactive = { ...obj } as T

    for (let key in obj) {
        if (Object.prototype.hasOwnProperty.call(obj, key)) {
            let value: Object = obj[key]

            Object.defineProperty(reactive, key, {
                get(): Object {
                    // 依赖收集
                    console.log(`读取属性: ${key}`)
                    // track(key) - 收集当前正在执行的副作用
                    return value
                },
                set(newValue: Object): void {
                    if (newValue !== value) {
                        console.log(`设置属性: ${key} = ${newValue}`)
                        value = newValue
                        // trigger(key) - 触发依赖此属性的副作用
                    }
                },
                enumerable: true,
                configurable: true
            })
        }
    }

    return reactive
}

// 2. Proxy代理方式(V2原理)
function createReactiveV2<T extends Object>(target: T): T {
    return new Proxy(target, {
        get(obj: T, key: string | symbol): Object {
            let value: Object = Reflect.get(obj, key) as Object
            // 依赖收集
            console.log(`Proxy读取: ${String(key)}`)
            // track(obj, key)

            // 如果值是对象,递归代理
            if (typeof value === 'object' && value !== null) {
                return createReactiveV2(value as Object)
            }
            return value
        },

        set(obj: T, key: string | symbol, value: Object): boolean {
            let oldValue: Object = Reflect.get(obj, key) as Object
            let result: boolean = Reflect.set(obj, key, value)

            if (oldValue !== value) {
                console.log(`Proxy设置: ${String(key)} = ${value}`)
                // trigger(obj, key)
            }

            return result
        }
    }) as T
}

// 3. 使用示例
interface ReactiveState {
    name: string
    count: number
    nested: { value: number }
}

// V1方式
let stateV1 = createReactiveV1<ReactiveState>({
    name: "测试",
    count: 0,
    nested: { value: 1 }
})

// V2方式
let stateV2 = createReactiveV2<ReactiveState>({
    name: "测试",
    count: 0,
    nested: { value: 1 }
})

5.5.2 3.4.2 依赖收集与触发更新

// 简化的响应式系统实现

// 依赖收集器
class DependencyTracker {
    private static currentEffect: (() => void) | null = null
    private static targetMap: Map<Object, Map<string, Set<() => void>>> =
        new Map()

    // 开始追踪依赖
    static startTrack(effect: () => void): void {
        DependencyTracker.currentEffect = effect
    }

    // 结束追踪
    static endTrack(): void {
        DependencyTracker.currentEffect = null
    }

    // 收集依赖(在getter中调用)
    static track(target: Object, key: string): void {
        if (!DependencyTracker.currentEffect) return

        let depsMap = DependencyTracker.targetMap.get(target)
        if (!depsMap) {
            depsMap = new Map()
            DependencyTracker.targetMap.set(target, depsMap)
        }

        let deps = depsMap.get(key)
        if (!deps) {
            deps = new Set()
            depsMap.set(key, deps)
        }

        deps.add(DependencyTracker.currentEffect)
    }

    // 触发更新(在setter中调用)
    static trigger(target: Object, key: string): void {
        let depsMap = DependencyTracker.targetMap.get(target)
        if (!depsMap) return

        let deps = depsMap.get(key)
        if (!deps) return

        deps.forEach((effect: () => void) => {
            effect()
        })
    }
}

// 创建响应式对象
function reactive<T extends Object>(target: T): T {
    return new Proxy(target, {
        get(obj: T, key: string | symbol): Object {
            let value: Object = Reflect.get(obj, key) as Object
            // 收集依赖
            DependencyTracker.track(obj, String(key))
            return value
        },
        set(obj: T, key: string | symbol, value: Object): boolean {
            let result: boolean = Reflect.set(obj, key, value)
            // 触发更新
            DependencyTracker.trigger(obj, String(key))
            return result
        }
    }) as T
}

// 副作用函数(类似组件的build方法)
function effect(fn: () => void): void {
    DependencyTracker.startTrack(fn)
    fn()
    DependencyTracker.endTrack()
}

// 使用示例
let state = reactive({ count: 0, name: "测试" })

// 模拟组件渲染
effect(() => {
    console.log(`渲染: count=${state.count}, name=${state.name}`)
})
// 输出: 渲染: count=0, name=测试

state.count = 1
// 输出: 渲染: count=1, name=测试

state.name = "新名称"
// 输出: 渲染: count=1, name=新名称

5.5.3 3.4.3 计算属性与派生状态

// 1. 计算属性实现
class ComputedProperty<T> {
    private value: T | null = null
    private dirty: boolean = true
    private getter: () => T
    private deps: Set<Set<() => void>> = new Set()

    constructor(getter: () => T) {
        this.getter = getter
    }

    get Value(): T {
        if (this.dirty) {
            this.value = this.getter()
            this.dirty = false
        }
        // 收集依赖
        DependencyTracker.track(this as unknown as Object, 'value')
        return this.value as T
    }

    // 标记为脏数据
    invalidate(): void {
        if (!this.dirty) {
            this.dirty = true
            // 触发依赖此计算属性的副作用
            DependencyTracker.trigger(this as unknown as Object, 'value')
        }
    }
}

// 2. 在状态管理中使用计算属性
@ObservedV2
class OrderModel {
    @Trace items: OrderItem[] = []
    @Trace couponCode: string = ""
    @Trace couponDiscount: number = 0

    // 计算属性 - 小计
    get subtotal(): number {
        return this.items.reduce(
            (sum: number, item: OrderItem) => sum + item.price * item.quantity,
            0
        )
    }

    // 计算属性 - 税费
    get tax(): number {
        return this.subtotal * 0.06  // 6%税率
    }

    // 计算属性 - 总价
    get total(): number {
        return this.subtotal + this.tax - this.couponDiscount
    }

    // 计算属性 - 商品总数
    get itemCount(): number {
        return this.items.reduce(
            (sum: number, item: OrderItem) => sum + item.quantity,
            0
        )
    }

    addItem(name: string, price: number, quantity: number = 1): void {
        this.items.push(new OrderItem(name, price, quantity))
    }

    applyCoupon(code: string, discount: number): void {
        this.couponCode = code
        this.couponDiscount = discount
    }
}

class OrderItem {
    name: string
    price: number
    quantity: number

    constructor(name: string, price: number, quantity: number) {
        this.name = name
        this.price = price
        this.quantity = quantity
    }
}

// 在组件中使用
@Component
struct OrderSummary {
    @ObjectLinkV2 order: OrderModel

    build() {
        Column({ space: 12 }) {
            // 商品列表
            ForEach(this.order.items, (item: OrderItem) => {
                Row() {
                    Text(item.name).layoutWeight(1)
                    Text(${item.price} x ${item.quantity}`)
                    Text(`= ¥${(item.price * item.quantity).toFixed(2)}`)
                        .width(80)
                        .textAlign(TextAlign.End)
                }
                .padding({ top: 8, bottom: 8 })
            }, (item: OrderItem) => item.name)

            Divider()

            // 费用明细
            Row() {
                Text("小计").layoutWeight(1)
                Text(${this.order.subtotal.toFixed(2)}`)
            }
            Row() {
                Text("税费 (6%)").layoutWeight(1)
                Text(${this.order.tax.toFixed(2)}`)
            }
            if (this.order.couponDiscount > 0) {
                Row() {
                    Text(`优惠券 (${this.order.couponCode})`)
                        .layoutWeight(1)
                    Text(`-¥${this.order.couponDiscount.toFixed(2)}`)
                        .fontColor('#4CAF50')
                }
            }

            Divider()

            Row() {
                Text("总计")
                    .fontSize(20)
                    .fontWeight(FontWeight.Bold)
                    .layoutWeight(1)
                Text(${this.order.total.toFixed(2)}`)
                    .fontSize(20)
                    .fontWeight(FontWeight.Bold)
                    .fontColor('#FF4444')
            }

            Text(`共 ${this.order.itemCount} 件商品`)
                .fontSize(12)
                .fontColor('#999999')
        }
        .padding(16)
        .backgroundColor('#FFFFFF')
        .borderRadius(12)
    }
}

5.5.4 3.4.4 状态变更的批处理

// 1. 自动批处理 - 同一事件处理中的多次修改
@Component
struct AutoBatchExample {
    @State x: number = 0
    @State y: number = 0
    @State z: number = 0
    @State renderCount: number = 0

    build() {
        // 每次build执行时计数
        this.renderCount++

        Column({ space: 12 }) {
            Text(`渲染次数: ${this.renderCount}`)
                .fontSize(14)
                .fontColor('#666666')
            Text(`X: ${this.x}, Y: ${this.y}, Z: ${this.z}`)
                .fontSize(18)

            Button("单次更新三个状态")
                .onClick(() => {
                    // 虽然修改了三个状态,但只会触发一次渲染
                    this.x++
                    this.y += 2
                    this.z += 3
                })

            Button("异步更新")
                .onClick(async () => {
                    // 异步操作中的状态更新
                    this.x++
                    await new Promise<void>((resolve) =>
                        setTimeout(resolve, 100)
                    )
                    // await之后的修改会触发新的渲染
                    this.y++
                })
        }
        .padding(24)
    }
}

// 2. 手动批处理 - 使用requestAnimationFrame
@Component
struct ManualBatchExample {
    @State positions: number[] = [0, 0, 0, 0, 0]
    @State frameCount: number = 0

    private animate(): void {
        // 使用requestAnimationFrame确保动画流畅
        requestAnimationFrame(() => {
            this.frameCount++
            // 在同一帧中更新所有位置
            for (let i: number = 0; i < this.positions.length; i++) {
                this.positions[i] = Math.sin(
                    (this.frameCount + i * 30) * Math.PI / 180
                ) * 50 + 50
            }
            // 递归调用继续动画
            this.animate()
        })
    }

    aboutToAppear(): void {
        this.animate()
    }

    build() {
        Column() {
            ForEach(this.positions, (pos: number, index: number) => {
                Row() {
                    Circle()
                        .width(20)
                        .height(20)
                        .fill('#2196F3')
                        .margin({ left: pos })
                    Text(`元素 ${index + 1}`)
                        .margin({ left: 12 })
                }
                .width('100%')
                .padding(8)
            }, (pos: number, index: number) => index.toString())
        }
    }
}

// 3. 避免状态更新的反模式
@Component
struct AntiPatternsExample {
    @State data: string[] = []

    build() {
        Column() {
            // 反模式1:在build中执行副作用
            // 错误:build() { this.fetchData() }

            // 反模式2:直接修改数组索引(可能不触发更新)
            // 错误:this.data[0] = "新值"
            // 正确:
            Button("正确更新数组")
                .onClick(() => {
                    // 创建新数组触发更新
                    let newData: string[] = [...this.data]
                    if (newData.length > 0) {
                        newData[0] = "已更新"
                    }
                    this.data = newData
                })

            // 反模式3:在循环中频繁修改状态
            // 错误:
            // for (let i = 0; i < 100; i++) {
            //     this.data.push(`item${i}`)  // 每次push都触发更新
            // }
            // 正确:
            Button("批量添加")
                .onClick(() => {
                    let newItems: string[] = []
                    for (let i: number = 0; i < 100; i++) {
                        newItems.push(`item${i}`)
                    }
                    this.data = [...this.data, ...newItems]  // 一次性更新
                })

            List() {
                ForEach(this.data, (item: string) => {
                    ListItem() {
                        Text(item)
                    }
                }, (item: string) => item)
            }
        }
    }
}

5.6 3.5 状态管理架构设计

5.6.1 3.5.1 状态分层策略

// 状态分为三个层次:UI状态、业务状态、应用状态

// 1. UI状态 - 仅在单个组件内使用
// 特征:生命周期与组件绑定,不需要跨组件共享
@Component
struct UIStateExample {
    // 展开/折叠状态
    @State isExpanded: boolean = false
    // 输入框焦点状态
    @State isFocused: boolean = false
    // 加载状态
    @State isLoading: boolean = false
    // 动画状态
    @State animationProgress: number = 0
    // 临时选择状态
    @State tempSelection: number = -1

    build() {
        Column() {
            // 可折叠面板
            Row() {
                Text("面板标题")
                    .layoutWeight(1)
                    .onClick(() => {
                        this.isExpanded = !this.isExpanded
                    })
                Text(this.isExpanded ? "▲" : "▼")
            }
            .padding(16)

            if (this.isExpanded) {
                Text("面板内容")
                    .padding(16)
            }

            // 加载按钮
            Button(this.isLoading ? "加载中..." : "提交")
                .enabled(!this.isLoading)
                .onClick(async () => {
                    this.isLoading = true
                    await this.submitData()
                    this.isLoading = false
                })
        }
    }

    private async submitData(): Promise<void> {
        await new Promise<void>((resolve) => setTimeout(resolve, 2000))
    }
}

// 2. 业务状态 - 跨组件共享的业务数据
@ObservedV2
class UserBusinessState {
    @Trace profile: UserProfile | null = null
    @Trace orders: OrderInfo[] = []
    @Trace favorites: number[] = []  // 收藏的商品ID列表
    @Trace isLoadingProfile: boolean = false
    @Trace isLoadingOrders: boolean = false

    private apiService: ApiService

    constructor(apiService: ApiService) {
        this.apiService = apiService
    }

    async loadProfile(userId: number): Promise<void> {
        this.isLoadingProfile = true
        try {
            this.profile = await this.apiService.getUserProfile(userId)
        } finally {
            this.isLoadingProfile = false
        }
    }

    async loadOrders(): Promise<void> {
        this.isLoadingOrders = true
        try {
            this.orders = await this.apiService.getUserOrders()
        } finally {
            this.isLoadingOrders = false
        }
    }

    async toggleFavorite(productId: number): Promise<void> {
        let index: number = this.favorites.indexOf(productId)
        if (index >= 0) {
            this.favorites.splice(index, 1)
            await this.apiService.removeFavorite(productId)
        } else {
            this.favorites.push(productId)
            await this.apiService.addFavorite(productId)
        }
    }

    get isFavorite(productId: number): boolean {
        return this.favorites.includes(productId)
    }
}

// 3. 应用状态 - 全局共享的应用级数据
@ObservedV2
class ApplicationState {
    @Trace isAuthenticated: boolean = false
    @Trace currentTheme: string = "light"
    @Trace networkStatus: NetworkStatus = NetworkStatus.Online
    @Trace appVersion: string = "1.0.0"
    @Trace lastSyncTime: number = 0

    // 单例模式
    private static instance: ApplicationState | null = null

    static getInstance(): ApplicationState {
        if (!ApplicationState.instance) {
            ApplicationState.instance = new ApplicationState()
        }
        return ApplicationState.instance
    }

    updateNetworkStatus(status: NetworkStatus): void {
        this.networkStatus = status
    }

    setAuthenticated(authenticated: boolean): void {
        this.isAuthenticated = authenticated
    }

    switchTheme(theme: string): void {
        this.currentTheme = theme
        // 同步到持久化存储
        AppStorage.set('theme', theme)
    }
}

enum NetworkStatus {
    Online,
    Offline,
    Poor
}

class UserProfile {
    id: number = 0
    name: string = ""
    avatar: string = ""
    email: string = ""
}

class OrderInfo {
    id: number = 0
    productName: string = ""
    amount: number = 0
    status: string = ""
}

// 4. 状态分层使用示例
@Component
struct LayeredStateExample {
    // UI状态
    @State showOrderDetail: boolean = false
    @State selectedOrderIndex: number = -1

    // 业务状态(通过依赖注入获取)
    @ObjectLinkV2 businessState: UserBusinessState

    // 应用状态
    @Consume('appState') appState: ApplicationState

    build() {
        Column() {
            // 网络状态指示器(应用状态)
            if (this.appState.networkStatus !== NetworkStatus.Online) {
                Text("网络连接异常")
                    .width('100%')
                    .padding(8)
                    .backgroundColor('#FFF3E0')
                    .fontColor('#E65100')
                    .textAlign(TextAlign.Center)
            }

            // 用户信息(业务状态)
            if (this.businessState.profile) {
                Row() {
                    Text(this.businessState.profile.name)
                        .fontSize(18)
                        .fontWeight(FontWeight.Bold)
                    Text(this.businessState.profile.email)
                        .fontSize(14)
                        .fontColor('#666666')
                }
                .padding(16)
            }

            // 订单列表(业务状态 + UI状态)
            List() {
                ForEach(this.businessState.orders,
                    (order: OrderInfo, index: number) => {
                        ListItem() {
                            OrderItemView({
                                order: order,
                                isSelected: index === this.selectedOrderIndex,
                                onSelect: () => {
                                    this.selectedOrderIndex = index
                                    this.showOrderDetail = true
                                }
                            })
                        }
                    },
                    (order: OrderInfo) => order.id.toString()
                )
            }
            .layoutWeight(1)
        }
    }
}

@Component
struct OrderItemView {
    order: OrderInfo = new OrderInfo()
    isSelected: boolean = false
    onSelect: () => void = () => {}

    build() {
        Row() {
            Column() {
                Text(this.order.productName)
                    .fontSize(16)
                Text(${this.order.amount} - ${this.order.status}`)
                    .fontSize(12)
                    .fontColor('#666666')
            }
            .layoutWeight(1)
            .alignItems(HorizontalAlign.Start)
        }
        .padding(16)
        .backgroundColor(this.isSelected ? '#E3F2FD' : '#FFFFFF')
        .onClick(() => { this.onSelect() })
    }
}

5.6.2 3.5.2 状态管理规范与约束

// 1. 状态管理命名规范
// 状态变量命名:使用camelCase
// 状态类型命名:使用PascalCase
// 事件处理函数:使用handle前缀或on前缀
// 计算属性:使用get前缀或is/has/can前缀

@ObservedV2
class NamingConvention {
    // 状态变量
    @Trace userName: string = ""
    @Trace isLoading: boolean = false
    @Trace errorMessage: string = ""

    // 计算属性
    get isValid(): boolean {
        return this.userName.length > 0
    }

    get displayName(): string {
        return this.userName || "匿名用户"
    }

    // 操作方法
    setName(name: string): void {
        this.userName = name
    }

    async loadData(): Promise<void> {
        this.isLoading = true
        this.errorMessage = ""
        try {
            // 加载数据
        } catch (error) {
            this.errorMessage = "加载失败"
        } finally {
            this.isLoading = false
        }
    }
}

// 2. 状态更新规范
class StateUpdateRules {
    // 规则1:使用不可变方式更新数组
    static addItem<T>(array: T[], item: T): T[] {
        return [...array, item]
    }

    static removeItem<T>(array: T[], index: number): T[] {
        return array.filter((_: T, i: number) => i !== index)
    }

    static updateItem<T>(array: T[], index: number, newItem: T): T[] {
        return array.map((item: T, i: number) =>
            i === index ? newItem : item
        )
    }

    // 规则2:使用不可变方式更新对象
    static updateObject<T extends Object>(obj: T, updates: Partial<T>): T {
        return { ...obj, ...updates }
    }

    // 规则3:状态更新应该通过明确的方法
    // 错误:直接修改深层属性
    // state.user.address.city = "新城市"
    // 正确:通过方法更新
    static updateUserCity(state: Object, city: string): void {
        let userState = state as Record<string, Object>
        let address = userState['address'] as Record<string, Object>
        address['city'] = city
    }
}

// 3. 状态管理约束检查器
class StateConstraintChecker {
    // 检查状态值是否合法
    static validateEmail(email: string): boolean {
        return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)
    }

    static validateAge(age: number): boolean {
        return age >= 0 && age <= 150
    }

    static validatePageSize(page: number, pageSize: number): boolean {
        return page >= 1 && pageSize >= 1 && pageSize <= 100
    }

    // 状态变更拦截器
    static withValidation<T>(
        setter: (value: T) => void,
        validator: (value: T) => boolean,
        defaultValue: T
    ): (value: T) => void {
        return (value: T): void => {
            if (validator(value)) {
                setter(value)
            } else {
                console.warn("状态值不合法,使用默认值")
                setter(defaultValue)
            }
        }
    }
}

5.6.3 3.5.3 状态持久化方案

// 1. 基于PersistentStorage的简单持久化
class SimplePersistence {
    static initialize(): void {
        // 用户偏好
        PersistentStorage.persistProp('theme', 'light')
        PersistentStorage.persistProp('fontSize', 14)
        PersistentStorage.persistProp('language', 'zh-CN')

        // 用户会话
        PersistentStorage.persistProp('lastUserId', 0)
        PersistentStorage.persistProp('rememberMe', false)

        // 应用状态
        PersistentStorage.persistProp('firstLaunch', true)
        PersistentStorage.persistProp('agreedTerms', false)
    }
}

// 2. 基于Preferences的复杂数据持久化
import { dataPreferences } from '@kit.ArkDataKit'

class PreferencesManager {
    private static preferences: dataPreferences.Preferences | null = null
    private static PREF_NAME: string = "app_data"

    static async initialize(context: common.Context): Promise<void> {
        PreferencesManager.preferences =
            await dataPreferences.getPreferences(context, PreferencesManager.PREF_NAME)
    }

    // 保存对象
    static async saveObject(key: string, value: Object): Promise<void> {
        if (PreferencesManager.preferences) {
            await PreferencesManager.preferences.put(key, JSON.stringify(value))
            await PreferencesManager.preferences.flush()
        }
    }

    // 读取对象
    static async loadObject<T>(key: string, defaultValue: T): Promise<T> {
        if (!PreferencesManager.preferences) return defaultValue

        let json: string =
            await PreferencesManager.preferences.get(key, '') as string
        if (json.length === 0) return defaultValue

        try {
            return JSON.parse(json) as T
        } catch {
            return defaultValue
        }
    }

    // 保存数组
    static async saveArray<T>(key: string, value: T[]): Promise<void> {
        await PreferencesManager.saveObject(key, value)
    }

    // 读取数组
    static async loadArray<T>(key: string): Promise<T[]> {
        return await PreferencesManager.loadObject<T[]>(key, [])
    }

    // 删除键
    static async remove(key: string): Promise<void> {
        if (PreferencesManager.preferences) {
            await PreferencesManager.preferences.delete(key)
            await PreferencesManager.preferences.flush()
        }
    }

    // 清除所有数据
    static async clear(): Promise<void> {
        if (PreferencesManager.preferences) {
            await PreferencesManager.preferences.clear()
            await PreferencesManager.preferences.flush()
        }
    }
}

// 3. 状态持久化服务
class PersistenceService {
    // 自动保存装饰器逻辑
    static async autoSave(
        key: string,
        data: Object,
        debounceMs: number = 1000
    ): Promise<void> {
        // 防抖保存
        let timerId: number = -1
        if (timerId !== -1) {
            clearTimeout(timerId)
        }
        timerId = setTimeout(async () => {
            await PreferencesManager.saveObject(key, data)
            timerId = -1
        }, debounceMs)
    }

    // 恢复状态
    static async restoreState<T>(
        key: string,
        defaultState: T
    ): Promise<T> {
        return await PreferencesManager.loadObject(key, defaultState)
    }
}

// 4. 使用示例
@Component
struct PersistentFormExample {
    @State formData: FormData = new FormData()
    @State isSaved: boolean = false
    private saveTimerId: number = -1

    aboutToAppear(): void {
        // 恢复之前保存的数据
        this.loadSavedData()
    }

    private async loadSavedData(): Promise<void> {
        this.formData = await PreferencesManager.loadObject(
            'formData',
            new FormData()
        )
    }

    private scheduleSave(): void {
        this.isSaved = false
        if (this.saveTimerId !== -1) {
            clearTimeout(this.saveTimerId)
        }
        this.saveTimerId = setTimeout(async () => {
            await PreferencesManager.saveObject('formData', this.formData)
            this.isSaved = true
            this.saveTimerId = -1
        }, 2000)  // 2秒防抖
    }

    aboutToDisappear(): void {
        // 组件销毁时立即保存
        if (this.saveTimerId !== -1) {
            clearTimeout(this.saveTimerId)
        }
        PreferencesManager.saveObject('formData', this.formData)
    }

    build() {
        Column({ space: 16 }) {
            Text("自动保存表单")
                .fontSize(20)
                .fontWeight(FontWeight.Bold)

            TextInput({ placeholder: "姓名", text: this.formData.name })
                .onChange((value: string) => {
                    this.formData.name = value
                    this.scheduleSave()
                })

            TextInput({ placeholder: "邮箱", text: this.formData.email })
                .onChange((value: string) => {
                    this.formData.email = value
                    this.scheduleSave()
                })

            TextInput({ placeholder: "备注", text: this.formData.notes })
                .onChange((value: string) => {
                    this.formData.notes = value
                    this.scheduleSave()
                })

            Text(this.isSaved ? "已保存" : "编辑中...")
                .fontSize(12)
                .fontColor(this.isSaved ? '#4CAF50' : '#FF9800')
        }
        .padding(24)
    }
}

class FormData {
    name: string = ""
    email: string = ""
    notes: string = ""
}

5.6.4 3.5.4 大型应用的状态管理实践

// 大型应用状态管理架构

// 1. 状态Store设计
// 每个功能模块有独立的Store

// 用户Store
@ObservedV2
class UserStore {
    @Trace currentUser: UserInfoV2 | null = null
    @Trace isAuthenticated: boolean = false
    @Trace permissions: string[] = []

    private static instance: UserStore | null = null

    static getInstance(): UserStore {
        if (!UserStore.instance) {
            UserStore.instance = new UserStore()
        }
        return UserStore.instance
    }

    async login(username: string, password: string): Promise<boolean> {
        try {
            // 调用登录API
            let result: LoginResult = await this.apiLogin(username, password)
            this.currentUser = result.user
            this.isAuthenticated = true
            this.permissions = result.permissions

            // 持久化登录状态
            await PreferencesManager.saveObject('auth', {
                token: result.token,
                userId: result.user.id
            })

            return true
        } catch (error) {
            return false
        }
    }

    logout(): void {
        this.currentUser = null
        this.isAuthenticated = false
        this.permissions = []
        PreferencesManager.remove('auth')
    }

    hasPermission(permission: string): boolean {
        return this.permissions.includes(permission)
    }

    private async apiLogin(
        username: string,
        password: string
    ): Promise<LoginResult> {
        return new Promise<LoginResult>((resolve) => {
            setTimeout(() => {
                resolve({
                    user: new UserInfoV2(1, username, `${username}@example.com`),
                    token: "mock_token",
                    permissions: ["read", "write"]
                })
            }, 1000)
        })
    }
}

class UserInfoV2 {
    id: number
    name: string
    email: string

    constructor(id: number, name: string, email: string) {
        this.id = id
        this.name = name
        this.email = email
    }
}

class LoginResult {
    user: UserInfoV2 = new UserInfoV2(0, "", "")
    token: string = ""
    permissions: string[] = []
}

// 商品Store
@ObservedV2
class ProductStore {
    @Trace products: ProductV2[] = []
    @Trace categories: string[] = []
    @Trace selectedCategory: string = "全部"
    @Trace searchKeyword: string = ""
    @Trace isLoading: boolean = false
    @Trace currentPage: number = 1
    @Trace hasMore: boolean = true

    private static instance: ProductStore | null = null

    static getInstance(): ProductStore {
        if (!ProductStore.instance) {
            ProductStore.instance = new ProductStore()
        }
        return ProductStore.instance
    }

    async loadProducts(reset: boolean = false): Promise<void> {
        if (this.isLoading) return
        if (!reset && !this.hasMore) return

        if (reset) {
            this.products = []
            this.currentPage = 1
            this.hasMore = true
        }

        this.isLoading = true
        try {
            let newProducts: ProductV2[] =
                await this.fetchProducts(this.currentPage)
            this.products = [...this.products, ...newProducts]
            this.hasMore = newProducts.length >= 20
            this.currentPage++
        } finally {
            this.isLoading = false
        }
    }

    get filteredProducts(): ProductV2[] {
        let result: ProductV2[] = this.products

        if (this.selectedCategory !== "全部") {
            result = result.filter(
                (p: ProductV2) => p.category === this.selectedCategory
            )
        }

        if (this.searchKeyword.length > 0) {
            result = result.filter(
                (p: ProductV2) => p.name.includes(this.searchKeyword)
            )
        }

        return result
    }

    private async fetchProducts(page: number): Promise<ProductV2[]> {
        return new Promise<ProductV2[]>((resolve) => {
            setTimeout(() => {
                let items: ProductV2[] = []
                for (let i: number = 0; i < 20; i++) {
                    let id: number = (page - 1) * 20 + i + 1
                    items.push(new ProductV2(
                        id,
                        `商品${id}`,
                        Math.floor(Math.random() * 1000) + 10,
                        "电子"
                    ))
                }
                resolve(items)
            }, 500)
        })
    }
}

class ProductV2 {
    id: number
    name: string
    price: number
    category: string

    constructor(id: number, name: string, price: number, category: string) {
        this.id = id
        this.name = name
        this.price = price
        this.category = category
    }
}

// 2. Store聚合器
class StoreManager {
    private static userStore: UserStore = UserStore.getInstance()
    private static productStore: ProductStore = ProductStore.getInstance()

    static getUser(): UserStore {
        return StoreManager.userStore
    }

    static getProduct(): ProductStore {
        return StoreManager.productStore
    }

    // 全局初始化
    static async initialize(context: common.Context): Promise<void> {
        // 初始化持久化
        await PreferencesManager.initialize(context)

        // 恢复登录状态
        let auth: Object =
            await PreferencesManager.loadObject('auth', {})
        let authRecord = auth as Record<string, Object>
        if (authRecord['token']) {
            StoreManager.userStore.isAuthenticated = true
        }
    }

    // 全局清理(用户登出时)
    static async cleanup(): Promise<void> {
        StoreManager.userStore.logout()
        StoreManager.productStore.products = []
    }
}

// 3. 在页面中使用Store
@Entry
@Component
struct MainPage {
    @ObjectLinkV2 userStore: UserStore = StoreManager.getUser()
    @ObjectLinkV2 productStore: ProductStore = StoreManager.getProduct()

    aboutToAppear(): void {
        if (this.userStore.isAuthenticated) {
            this.productStore.loadProducts()
        }
    }

    build() {
        Column() {
            // 顶部用户信息栏
            Row() {
                if (this.userStore.isAuthenticated && this.userStore.currentUser) {
                    Text(`欢迎, ${this.userStore.currentUser.name}`)
                        .fontSize(16)
                    Button("退出")
                        .fontSize(12)
                        .onClick(() => { StoreManager.cleanup() })
                } else {
                    Text("未登录")
                        .fontSize(16)
                    Button("登录")
                        .fontSize(12)
                        .onClick(() => {
                            this.userStore.login("testuser", "password")
                        })
                }
            }
            .width('100%')
            .justifyContent(FlexAlign.SpaceBetween)
            .padding(16)

            // 搜索和分类
            Row() {
                TextInput({ placeholder: "搜索商品..." })
                    .layoutWeight(1)
                    .onChange((value: string) => {
                        this.productStore.searchKeyword = value
                    })
            }
            .padding({ left: 16, right: 16 })

            // 商品列表
            List() {
                ForEach(this.productStore.filteredProducts,
                    (product: ProductV2) => {
                        ListItem() {
                            Row() {
                                Text(product.name)
                                    .layoutWeight(1)
                                Text(${product.price}`)
                                    .fontColor('#FF4444')
                            }
                            .padding(16)
                        }
                    },
                    (product: ProductV2) => product.id.toString()
                )
            }
            .layoutWeight(1)
            .onReachEnd(() => {
                // 滚动到底部加载更多
                this.productStore.loadProducts()
            })

            // 加载指示器
            if (this.productStore.isLoading) {
                LoadingProgress()
                    .width(40)
                    .height(40)
            }
        }
    }
}

5.7 本章小结

本章全面介绍了HarmonyOS高级状态管理的核心知识:

  1. 状态管理V2:理解了V2相比V1的改进(更精确的观察粒度、更简洁的API、更好的性能),掌握了@ObservedV2、@ObjectLinkV2@Local@Param等新装饰器的使用方法和迁移策略

  2. 全局状态管理:掌握了AppStorage(应用级)、LocalStorage(页面级)、PersistentStorage(持久化)和Environment(环境变量)四种全局状态方案的使用场景和最佳实践。

  3. 组件间状态共享:深入理解了@State/@Prop/@Link的数据流方向,掌握了@Provide/@Consume跨层级通信和@Watch状态监听的实现方式,了解了状态管理对性能的影响。

  4. 响应式数据流:理解了数据劫持(Object.defineProperty和Proxy)的底层原理,掌握了依赖收集和触发更新的机制,学习了计算属性和批处理技术。

  5. 状态管理架构:掌握了状态分层策略(UI状态、业务状态、应用状态),了解了状态管理规范和约束,学习了多种持久化方案和大型应用的状态管理实践。


5.8 练习题

5.8.1 一、单选题

1. 在状态管理V2中,用于标记需要被追踪的类属性的装饰器是?

A. @ObservedV2 B. @Trace C. @ObjectLinkV2 D. @Local

答案:B

解析: 在V2状态管理中,@ObservedV2用于标记类使其具备观察能力,而@Trace用于标记类中需要被追踪的具体属性。只有被@Trace标记的属性变化才会触发UI更新。@ObjectLinkV2用于在子组件中接收@ObservedV2对象@Local用于组件内部本地状态


2. 以下关于@Provide/@Consume的描述,正确的是?

A. @Provide只能向直接子组件传递数据 B. @Consume可以修改@Provide的值并同步回祖先组件 C. @Provide/@Consume可以跨越多层组件传递状态 D. @Consume必须提供默认值

答案:C

解析: @Provide/@Consume的核心优势是可以跨越多层组件直接传递状态,不需要逐层通过@Prop/@Link传递@Provide标记的值可以被任意深度的后代组件通过@Consume获取@Consume获取的值是可以修改的(双向绑定)。


3. AppStorage和LocalStorage的主要区别是?

A. AppStorage用于组件内部,LocalStorage用于全局 B. AppStorage是应用级全局存储,LocalStorage是页面级存储 C. AppStorage支持持久化,LocalStorage不支持 D. 没有区别,只是名称不同

答案:B

解析: AppStorage是应用级别的全局状态存储,所有页面和组件都可以访问;LocalStorage是页面(UIAbility)级别的存储,每个页面有独立的LocalStorage实例。两者都不直接提供持久化能力,持久化需要配合PersistentStorage使用。


5.8.2 二、多选题

4. 以下哪些装饰器属于状态管理V2的新特性?

A. @ObservedV2 B. @ObjectLinkV2 C. @Local D. @Monitor

答案:A、B、C、D

解析: 以上四个装饰器都是V2状态管理引入的新特性。@ObservedV2替代@Observed@ObjectLinkV2替代@ObjectLink@Local替代@State(用于组件内部状态),@Monitor替代@Watch(支持监听多个属性)。


5. 以下关于PersistentStorage的描述,正确的有哪些?

A. 数据会在应用重启后保留 B. 通过persistProp方法配置需要持久化的属性 C. 只能存储基本数据类型(string、number、boolean) D. 配合@StorageLink使用可以实现自动持久化

答案:A、B、D

解析: PersistentStorage提供数据持久化能力,数据在应用重启后仍然保留。通过persistProp方法配置哪些属性需要持久化,配合@StorageLink可以实现修改自动持久化。它支持string、number、boolean等基本类型,不直接支持复杂对象的持久化。


5.8.3 三、判断题

6. @Prop装饰器实现的是父子组件之间的双向数据绑定

答案:错误

解析: @Prop实现的是父到子的单向数据流。子组件可以修改@Prop值的本地副本,但修改不会同步回父组件。如果需要双向绑定,应使用@Link装饰器(V1)或@Event装饰器(V2)。


7. 在同一个事件处理函数中多次修改@State状态,只会触发一次UI重渲染。

答案:正确

解析: HarmonyOS框架会自动对同一事件处理函数(同步代码块)中的多次状态修改进行批处理,合并为一次UI更新。这避免了频繁的状态修改导致的多次重渲染,提升了性能。但异步操作(await之后)的修改会触发新的渲染周期。


8. @ObservedV2标记的类,其所有属性变化都会被自动追踪,无需额外装饰器。

答案:错误

解析: @ObservedV2只标记类具备观察能力,但具体哪些属性需要被追踪,需要使用@Trace装饰器显式标记。只有被@Trace标记的属性变化才会触发依赖该属性的UI组件重渲染。这种设计提供了更精确的控制,避免不必要的更新。