HarmonyOS应用<节气通>开发第33篇:状态管理实战

引言

状态管理是HarmonyOS应用开发中的核心概念。本文将深入探讨ArkTS中的状态管理机制,包括:

  • 组件状态管理
  • 全局状态管理
  • 状态同步策略
  • 复杂状态场景处理

通过本文,你将掌握如何在实际项目中高效管理应用状态。


学习目标

完成本文后,你将能够:

  • ✅ 理解组件状态管理
  • ✅ 实现全局状态管理
  • ✅ 处理状态同步
  • ✅ 解决复杂状态场景

需求分析

状态管理场景

场景 描述 技术要点
组件状态 单个组件的状态 @State、@Prop、@Link
全局状态 跨组件共享状态 全局Store、事件总线
异步状态 异步数据加载 Promise、async/await
复杂状态 多层级状态嵌套 状态树、状态切片

状态管理方案对比与选型

常见状态管理方案

方案 适用场景 优点 缺点
ArkTS内置状态 组件内状态、父子组件通信 轻量、简单、响应式更新 不支持跨页面共享
全局单例Store 全局状态共享 集中管理、易于维护 需要手动处理订阅
事件总线 组件间解耦通信 解耦性好、灵活 难以追踪数据流
路由参数 页面间数据传递 简单直接 只适合少量数据
持久化存储 跨会话状态保持 数据持久化 性能开销、异步操作

方案选型建议

小型应用(单页面为主):

  • 使用ArkTS内置状态即可满足需求
  • 简单的全局状态可以用单例Store

中型应用(多页面、复杂交互):

  • 组合使用:内置状态 + 全局Store + 事件总线
  • 考虑使用状态切片管理不同业务模块

大型应用(复杂状态、多人协作):

  • 需要更完善的状态管理方案
  • 可考虑引入状态管理库或设计更完善的架构

状态管理架构设计原则

  1. 单一职责原则:每个状态只负责一个业务领域
  2. 最小化状态:只维护必要的状态,避免冗余
  3. 状态不可变性:状态更新通过替换而非修改
  4. 可预测性:状态变化应该是可追踪和可预测的
  5. 易于测试:状态管理逻辑应该易于单元测试

核心实现

步骤1: 组件状态管理

typescript 复制代码
// 组件状态管理示例
@Entry
@Component
struct ComponentStateDemo {
  // 本地状态 - 组件内部使用
  @State count: number = 0;
  @State isExpanded: boolean = false;
  @State userInfo: UserInfo | null = null;
  
  // 从父组件接收的状态 - 单向传递
  @Prop title: string = '';
  
  // 双向绑定状态 - 父子组件同步
  @Link syncValue: number;
  
  // 计算属性 - 根据其他状态计算
  @Computed get total(): number {
    return this.count * 2;
  }
  
  // 异步加载数据
  async aboutToAppear() {
    this.userInfo = await this.fetchUserInfo();
  }
  
  async fetchUserInfo(): Promise<UserInfo> {
    // 模拟网络请求
    return new Promise(resolve => {
      setTimeout(() => {
        resolve({
          id: '1',
          name: '张三',
          avatar: '',
          level: 5
        });
      }, 1000);
    });
  }
  
  build() {
    Column({ space: 12 }) {
      // 使用@Prop
      Text(this.title)
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
      
      // 使用@State
      Row({ space: 12 }) {
        Button('+')
          .onClick(() => this.count++)
        
        Text(`Count: ${this.count}`)
        
        Button('-')
          .onClick(() => this.count--)
      }
      
      // 使用@Computed
      Text(`Total: ${this.total}`)
        .fontSize(16)
        .fontColor('#999999')
      
      // 使用@Link
      Row({ space: 12 }) {
        Text('同步值:')
        TextInput({ placeholder: '输入数字' })
          .type(InputType.Number)
          .onChange((value: string) => {
            this.syncValue = parseInt(value) || 0;
          })
      }
      
      // 条件渲染
      if (this.userInfo) {
        Card() {
          Row({ space: 12 }) {
            Circle()
              .width(40)
              .height(40)
              .fillColor('#E8F5E9')
            
            Column({ space: 4 }) {
              Text(this.userInfo.name)
                .fontSize(16)
                .fontWeight(FontWeight.Medium)
              
              Text(`等级: ${this.userInfo.level}`)
                .fontSize(12)
                .fontColor('#999999')
            }
          }
          .padding(12)
        }
      } else {
        // 加载状态
        LoadingProgress()
          .width(40)
          .height(40)
      }
      
      // 展开/收起
      Button(this.isExpanded ? '收起' : '展开')
        .onClick(() => {
          this.isExpanded = !this.isExpanded;
        })
      
      if (this.isExpanded) {
        Text('展开的内容...')
          .fontSize(14)
          .fontColor('#666666')
          .padding(12)
          .backgroundColor('#FFFFFF')
          .borderRadius(8)
      }
    }
    .width('100%')
    .height('100%')
    .padding(16)
    .justifyContent(FlexAlign.Center)
    .backgroundColor('#F8F7F2')
  }
}

interface UserInfo {
  id: string;
  name: string;
  avatar: string;
  level: number;
}

设计要点:

  • @State 本地状态
  • @Prop 单向传递
  • @Link 双向绑定
  • @Computed 计算属性
  • 条件渲染

步骤2: 全局状态管理

typescript 复制代码
// 全局状态管理示例
class GlobalStore {
  // 单例实例
  private static instance: GlobalStore;
  
  // 用户状态
  private userState: UserState = {
    isLoggedIn: false,
    userInfo: null,
    token: ''
  };
  
  // 学习状态
  private learningState: LearningState = {
    totalDays: 0,
    articlesRead: 0,
    score: 0
  };
  
  // 监听者列表
  private listeners: Map<string, Set<() => void>> = new Map();
  
  private constructor() {}
  
  static getInstance(): GlobalStore {
    if (!GlobalStore.instance) {
      GlobalStore.instance = new GlobalStore();
    }
    return GlobalStore.instance;
  }
  
  // 用户状态操作
  getUserState(): UserState {
    return { ...this.userState };
  }
  
  setUserState(state: Partial<UserState>): void {
    this.userState = { ...this.userState, ...state };
    this.notify('user');
  }
  
  // 学习状态操作
  getLearningState(): LearningState {
    return { ...this.learningState };
  }
  
  updateLearningState(state: Partial<LearningState>): void {
    this.learningState = { ...this.learningState, ...state };
    this.notify('learning');
  }
  
  // 订阅状态变化
  subscribe(key: string, listener: () => void): void {
    if (!this.listeners.has(key)) {
      this.listeners.set(key, new Set());
    }
    this.listeners.get(key)?.add(listener);
  }
  
  // 取消订阅
  unsubscribe(key: string, listener: () => void): void {
    this.listeners.get(key)?.delete(listener);
  }
  
  // 通知监听者
  private notify(key: string): void {
    this.listeners.get(key)?.forEach(listener => listener());
  }
  
  // 清除所有状态
  clear(): void {
    this.userState = {
      isLoggedIn: false,
      userInfo: null,
      token: ''
    };
    this.notify('user');
  }
}

interface UserState {
  isLoggedIn: boolean;
  userInfo: UserInfo | null;
  token: string;
}

interface LearningState {
  totalDays: number;
  articlesRead: number;
  score: number;
}

interface UserInfo {
  id: string;
  name: string;
  avatar: string;
}

// 创建全局实例
export const globalStore = GlobalStore.getInstance();

// 在组件中使用全局状态
@Entry
@Component
struct GlobalStateDemo {
  @State userState: UserState = globalStore.getUserState();
  @State learningState: LearningState = globalStore.getLearningState();
  
  aboutToAppear() {
    // 订阅用户状态变化
    globalStore.subscribe('user', () => {
      this.userState = globalStore.getUserState();
    });
    
    // 订阅学习状态变化
    globalStore.subscribe('learning', () => {
      this.learningState = globalStore.getLearningState();
    });
  }
  
  aboutToDisappear() {
    // 取消订阅
    globalStore.unsubscribe('user', this.handleUserChange);
    globalStore.unsubscribe('learning', this.handleLearningChange);
  }
  
  handleUserChange = () => {
    this.userState = globalStore.getUserState();
  }
  
  handleLearningChange = () => {
    this.learningState = globalStore.getLearningState();
  }
  
  onLogin() {
    globalStore.setUserState({
      isLoggedIn: true,
      userInfo: {
        id: '1',
        name: '张三',
        avatar: ''
      },
      token: 'mock_token'
    });
  }
  
  updateScore() {
    globalStore.updateLearningState({
      score: this.learningState.score + 100
    });
  }
  
  build() {
    Column({ space: 16 }) {
      if (this.userState.isLoggedIn) {
        Text(`欢迎, ${this.userState.userInfo?.name}`)
          .fontSize(20)
          .fontWeight(FontWeight.Bold)
        
        Button('更新积分')
          .onClick(() => this.updateScore())
      } else {
        Button('登录')
          .onClick(() => this.onLogin())
      }
      
      Text(`学习天数: ${this.learningState.totalDays}`)
      Text(`阅读文章: ${this.learningState.articlesRead}`)
      Text(`积分: ${this.learningState.score}`)
    }
    .width('100%')
    .height('100%')
    .padding(16)
    .justifyContent(FlexAlign.Center)
    .backgroundColor('#F8F7F2')
  }
}

设计要点:

  • 单例模式
  • 状态订阅机制
  • 状态变更通知

步骤3: 状态同步策略

typescript 复制代码
// 状态同步策略示例

/**
 * 策略1: 事件总线模式
 * 通过事件发布/订阅实现组件间通信
 */
class EventBus {
  private listeners: Map<string, Set<(...args: any[]) => void>> = new Map();
  
  emit(event: string, ...args: any[]): void {
    this.listeners.get(event)?.forEach(listener => listener(...args));
  }
  
  on(event: string, listener: (...args: any[]) => void): void {
    if (!this.listeners.has(event)) {
      this.listeners.set(event, new Set());
    }
    this.listeners.get(event)?.add(listener);
  }
  
  off(event: string, listener: (...args: any[]) => void): void {
    this.listeners.get(event)?.delete(listener);
  }
}

const eventBus = new EventBus();

// 使用事件总线
@Entry
@Component
struct EventBusDemo {
  @State message: string = '';
  
  aboutToAppear() {
    // 订阅事件
    eventBus.on('message_update', (msg: string) => {
      this.message = msg;
    });
  }
  
  aboutToDisappear() {
    // 取消订阅
    eventBus.off('message_update', this.handleMessageUpdate);
  }
  
  handleMessageUpdate = (msg: string) => {
    this.message = msg;
  }
  
  sendMessage() {
    // 发布事件
    eventBus.emit('message_update', 'Hello from EventBus!');
  }
  
  build() {
    Column({ space: 16 }) {
      Text(this.message)
        .fontSize(18)
      
      Button('发送消息')
        .onClick(() => this.sendMessage())
    }
    .width('100%')
    .height('100%')
    .padding(16)
    .justifyContent(FlexAlign.Center)
  }
}

/**
 * 策略2: 路由参数传递
 * 通过路由跳转传递状态
 */
@Entry
@Component
struct RouterParamsDemo {
  goToDetail() {
    // 传递参数
    router.pushUrl({
      url: 'pages/Detail',
      params: {
        id: '1',
        name: '立春',
        type: 'solar_term'
      }
    });
  }
  
  build() {
    Button('跳转到详情页')
      .onClick(() => this.goToDetail())
  }
}

// 接收参数的页面
@Entry
@Component
struct DetailPage {
  @State params: Record<string, any> = {};
  
  aboutToAppear() {
    // 获取路由参数
    this.params = router.getParams() || {};
  }
  
  build() {
    Column({ space: 8 }) {
      Text(`ID: ${this.params.id}`)
      Text(`名称: ${this.params.name}`)
      Text(`类型: ${this.params.type}`)
    }
    .width('100%')
    .height('100%')
    .padding(16)
    .justifyContent(FlexAlign.Center)
  }
}

/**
 * 策略3: 持久化存储
 * 通过本地存储同步状态
 */
@Entry
@Component
struct StorageSyncDemo {
  @State count: number = 0;
  
  aboutToAppear() {
    // 从存储读取
    storage.get('count', '0').then(value => {
      this.count = parseInt(value);
    });
  }
  
  onIncrement() {
    this.count++;
    // 保存到存储
    storage.set('count', this.count.toString());
  }
  
  build() {
    Column({ space: 16 }) {
      Text(`Count: ${this.count}`)
        .fontSize(20)
      
      Button('+')
        .onClick(() => this.onIncrement())
    }
    .width('100%')
    .height('100%')
    .padding(16)
    .justifyContent(FlexAlign.Center)
  }
}

// Mock storage
const storage = {
  async get(key: string, defaultValue: string): Promise<string> {
    return defaultValue;
  },
  async set(key: string, value: string): Promise<void> {}
};

设计要点:

  • 事件总线模式
  • 路由参数传递
  • 持久化存储同步

步骤4: 复杂状态场景处理

typescript 复制代码
// 复杂状态场景示例

/**
 * 场景1: 表单状态管理
 */
@Entry
@Component
struct FormStateDemo {
  @State formData: FormData = {
    username: '',
    email: '',
    password: '',
    rememberMe: false
  };
  
  @State errors: FormErrors = {};
  
  validateForm(): boolean {
    this.errors = {};
    
    if (!this.formData.username.trim()) {
      this.errors.username = '请输入用户名';
    }
    
    if (!this.formData.email.trim()) {
      this.errors.email = '请输入邮箱';
    } else if (!this.isValidEmail(this.formData.email)) {
      this.errors.email = '请输入有效的邮箱地址';
    }
    
    if (!this.formData.password) {
      this.errors.password = '请输入密码';
    } else if (this.formData.password.length < 6) {
      this.errors.password = '密码长度至少6位';
    }
    
    return Object.keys(this.errors).length === 0;
  }
  
  isValidEmail(email: string): boolean {
    return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
  }
  
  onSubmit() {
    if (this.validateForm()) {
      // 提交表单
      console.log('表单验证通过:', this.formData);
    }
  }
  
  build() {
    Column({ space: 12 }) {
      // 用户名输入
      Column({ space: 4 }) {
        TextInput({ placeholder: '用户名' })
          .onChange((value: string) => {
            this.formData.username = value;
            if (this.errors.username) {
              delete this.errors.username;
            }
          })
        
        if (this.errors.username) {
          Text(this.errors.username)
            .fontSize(12)
            .fontColor('#FF5252')
        }
      }
      
      // 邮箱输入
      Column({ space: 4 }) {
        TextInput({ placeholder: '邮箱' })
          .onChange((value: string) => {
            this.formData.email = value;
            if (this.errors.email) {
              delete this.errors.email;
            }
          })
        
        if (this.errors.email) {
          Text(this.errors.email)
            .fontSize(12)
            .fontColor('#FF5252')
        }
      }
      
      // 密码输入
      Column({ space: 4 }) {
        TextInput({ placeholder: '密码' })
          .type(InputType.Password)
          .onChange((value: string) => {
            this.formData.password = value;
            if (this.errors.password) {
              delete this.errors.password;
            }
          })
        
        if (this.errors.password) {
          Text(this.errors.password)
            .fontSize(12)
            .fontColor('#FF5252')
        }
      }
      
      // 记住我
      Row({ space: 8 }) {
        Switch({ selected: this.formData.rememberMe })
          .onChange((isOn: boolean) => {
            this.formData.rememberMe = isOn;
          })
        
        Text('记住我')
          .fontSize(14)
          .fontColor('#666666')
      }
      
      Button('提交')
        .width('100%')
        .height(48)
        .backgroundColor('#4A9B6D')
        .fontColor('#FFFFFF')
        .borderRadius(24)
        .onClick(() => this.onSubmit())
    }
    .width('92%')
    .height('100%')
    .padding(16)
    .justifyContent(FlexAlign.Center)
    .backgroundColor('#F8F7F2')
  }
}

interface FormData {
  username: string;
  email: string;
  password: string;
  rememberMe: boolean;
}

interface FormErrors {
  username?: string;
  email?: string;
  password?: string;
}

/**
 * 场景2: 列表状态管理
 */
@Entry
@Component
struct ListStateDemo {
  @State items: ListItem[] = [];
  @State isLoading: boolean = false;
  @State hasMore: boolean = true;
  @State page: number = 1;
  
  async aboutToAppear() {
    await this.loadData();
  }
  
  async loadData() {
    this.isLoading = true;
    
    // 模拟网络请求
    await new Promise(resolve => setTimeout(resolve, 1000));
    
    // 模拟数据
    const newItems: ListItem[] = [
      { id: `${this.page}-1`, title: `项目 ${this.page}-1` },
      { id: `${this.page}-2`, title: `项目 ${this.page}-2` },
      { id: `${this.page}-3`, title: `项目 ${this.page}-3` }
    ];
    
    this.items = [...this.items, ...newItems];
    this.isLoading = false;
    
    // 模拟分页结束
    if (this.page >= 5) {
      this.hasMore = false;
    }
  }
  
  onLoadMore() {
    if (!this.isLoading && this.hasMore) {
      this.page++;
      this.loadData();
    }
  }
  
  onRefresh() {
    this.page = 1;
    this.items = [];
    this.hasMore = true;
    this.loadData();
  }
  
  build() {
    List({ space: 8, initialIndex: 0 }) {
      // 下拉刷新
      ListItem() {
        Refresh({ refreshing: this.isLoading, onRefresh: () => this.onRefresh() }) {
          // 刷新内容
        }
      }
      
      // 列表项
      ForEach(this.items, (item: ListItem) => {
        ListItem() {
          Text(item.title)
            .fontSize(16)
            .fontColor('#333333')
            .width('100%')
            .height(48)
            .padding({ left: 16 })
            .backgroundColor('#FFFFFF')
            .borderRadius(8)
            .justifyContent(FlexAlign.Center)
        }
      }, (item: ListItem) => item.id)
      
      // 加载更多
      if (this.hasMore) {
        ListItem() {
          Row({ space: 8 }) {
            if (this.isLoading) {
              LoadingProgress().width(20).height(20)
              Text('加载中...')
            } else {
              Text('点击加载更多')
            }
          }
          .width('100%')
          .height(48)
          .justifyContent(FlexAlign.Center)
          .onClick(() => this.onLoadMore())
        }
      } else {
        ListItem() {
          Text('没有更多数据')
            .fontSize(14)
            .fontColor('#999999')
            .width('100%')
            .height(48)
            .justifyContent(FlexAlign.Center)
        }
      }
    }
    .width('92%')
    .height('100%')
    .padding({ top: 16 })
  }
}

interface ListItem {
  id: string;
  title: string;
}

设计要点:

  • 表单状态管理
  • 列表分页状态
  • 下拉刷新和加载更多

实际应用场景

场景1: 用户认证状态管理

typescript 复制代码
// 用户认证状态管理
class AuthStore {
  private static instance: AuthStore;
  
  private user: User | null = null;
  private token: string = '';
  private isLoggedIn: boolean = false;
  private listeners: Set<() => void> = new Set();
  
  private constructor() {}
  
  static getInstance(): AuthStore {
    if (!AuthStore.instance) {
      AuthStore.instance = new AuthStore();
    }
    return AuthStore.instance;
  }
  
  // 登录
  async login(credentials: LoginCredentials): Promise<void> {
    // 调用登录API
    // const response = await AuthApi.login(credentials);
    
    // 模拟登录成功
    this.user = {
      id: '1',
      name: '张三',
      email: 'zhangsan@example.com',
      avatar: ''
    };
    this.token = 'mock_jwt_token';
    this.isLoggedIn = true;
    
    // 保存到持久化存储
    await secureStorage.setObject('user', this.user);
    await secureStorage.set('token', this.token);
    
    this.notifyListeners();
  }
  
  // 登出
  async logout(): Promise<void> {
    this.user = null;
    this.token = '';
    this.isLoggedIn = false;
    
    // 清除持久化存储
    await secureStorage.remove('user');
    await secureStorage.remove('token');
    
    this.notifyListeners();
  }
  
  // 自动登录
  async autoLogin(): Promise<boolean> {
    const savedUser = await secureStorage.getObject<User>('user');
    const savedToken = await secureStorage.get('token');
    
    if (savedUser && savedToken) {
      this.user = savedUser;
      this.token = savedToken;
      this.isLoggedIn = true;
      this.notifyListeners();
      return true;
    }
    
    return false;
  }
  
  // 获取用户信息
  getUser(): User | null {
    return this.user;
  }
  
  // 获取Token
  getToken(): string {
    return this.token;
  }
  
  // 是否登录
  getIsLoggedIn(): boolean {
    return this.isLoggedIn;
  }
  
  // 订阅状态变化
  subscribe(listener: () => void): void {
    this.listeners.add(listener);
  }
  
  // 取消订阅
  unsubscribe(listener: () => void): void {
    this.listeners.delete(listener);
  }
  
  // 通知监听者
  private notifyListeners(): void {
    this.listeners.forEach(listener => listener());
  }
}

interface User {
  id: string;
  name: string;
  email: string;
  avatar: string;
}

interface LoginCredentials {
  email: string;
  password: string;
}

// Mock secureStorage
const secureStorage = {
  async setObject(key: string, value: any): Promise<void> {},
  async getObject<T>(key: string): Promise<T | null> { return null; },
  async set(key: string, value: string): Promise<void> {},
  async get(key: string): Promise<string> { return ''; },
  async remove(key: string): Promise<void> {}
};

// 导出实例
export const authStore = AuthStore.getInstance();

场景2: 购物车状态管理

typescript 复制代码
// 购物车状态管理
class CartStore {
  private static instance: CartStore;
  
  private items: CartItem[] = [];
  private listeners: Set<() => void> = new Set();
  
  private constructor() {}
  
  static getInstance(): CartStore {
    if (!CartStore.instance) {
      CartStore.instance = new CartStore();
    }
    return CartStore.instance;
  }
  
  // 添加商品
  addItem(item: CartItem): void {
    const existingIndex = this.items.findIndex(i => i.id === item.id);
    
    if (existingIndex >= 0) {
      // 更新数量
      this.items[existingIndex].quantity += item.quantity;
    } else {
      // 添加新商品
      this.items.push({ ...item });
    }
    
    this.notifyListeners();
    this.persist();
  }
  
  // 更新商品数量
  updateQuantity(id: string, quantity: number): void {
    const index = this.items.findIndex(i => i.id === id);
    
    if (index >= 0) {
      if (quantity <= 0) {
        this.removeItem(id);
      } else {
        this.items[index].quantity = quantity;
        this.notifyListeners();
        this.persist();
      }
    }
  }
  
  // 删除商品
  removeItem(id: string): void {
    this.items = this.items.filter(i => i.id !== id);
    this.notifyListeners();
    this.persist();
  }
  
  // 清空购物车
  clear(): void {
    this.items = [];
    this.notifyListeners();
    this.persist();
  }
  
  // 获取购物车列表
  getItems(): CartItem[] {
    return [...this.items];
  }
  
  // 获取购物车数量
  getTotalQuantity(): number {
    return this.items.reduce((sum, item) => sum + item.quantity, 0);
  }
  
  // 获取购物车总价
  getTotalPrice(): number {
    return this.items.reduce((sum, item) => sum + item.price * item.quantity, 0);
  }
  
  // 从持久化存储加载
  async load(): Promise<void> {
    const saved = await storage.get('cart', '');
    if (saved) {
      this.items = JSON.parse(saved);
      this.notifyListeners();
    }
  }
  
  // 持久化保存
  private async persist(): Promise<void> {
    await storage.set('cart', JSON.stringify(this.items));
  }
  
  // 订阅
  subscribe(listener: () => void): void {
    this.listeners.add(listener);
  }
  
  // 取消订阅
  unsubscribe(listener: () => void): void {
    this.listeners.delete(listener);
  }
  
  // 通知
  private notifyListeners(): void {
    this.listeners.forEach(listener => listener());
  }
}

interface CartItem {
  id: string;
  name: string;
  price: number;
  quantity: number;
  image?: string;
}

// Mock storage
const storage = {
  async get(key: string, defaultValue: string): Promise<string> { return defaultValue; },
  async set(key: string, value: string): Promise<void> {}
};

// 导出实例
export const cartStore = CartStore.getInstance();

常见问题与解决方案

问题1: 状态更新不触发UI刷新

现象: 修改状态后UI没有更新

原因:

  • 对象/数组直接修改而不是替换
  • 使用了不可变数据的错误方式

解决方案:

typescript 复制代码
// 错误方式 - 直接修改数组
this.items.push(newItem); // UI不会刷新

// 正确方式 - 创建新数组
this.items = [...this.items, newItem]; // UI会刷新

// 错误方式 - 直接修改对象属性
this.user.name = '新名字'; // UI不会刷新

// 正确方式 - 创建新对象
this.user = { ...this.user, name: '新名字' }; // UI会刷新

问题2: 状态订阅导致内存泄漏

现象: 页面销毁后订阅仍在执行

解决方案:

typescript 复制代码
@Entry
@Component
struct SafeSubscriptionPage {
  private unsubscribeUser?: () => void;
  private unsubscribeCart?: () => void;
  
  aboutToAppear() {
    // 订阅用户状态
    this.unsubscribeUser = globalStore.subscribe('user', () => {
      // 处理状态变化
    });
    
    // 订阅购物车状态
    this.unsubscribeCart = cartStore.subscribe(() => {
      // 处理状态变化
    });
  }
  
  aboutToDisappear() {
    // 取消订阅
    if (this.unsubscribeUser) {
      this.unsubscribeUser();
    }
    if (this.unsubscribeCart) {
      this.unsubscribeCart();
    }
  }
  
  build() {
    // 页面内容
  }
}

问题3: 异步操作导致状态不一致

现象: 多个异步操作同时修改状态导致数据混乱

解决方案:

typescript 复制代码
// 使用状态锁防止并发问题
class AsyncSafeStore {
  private isUpdating: boolean = false;
  
  async updateData(newData: any): Promise<void> {
    // 如果正在更新,等待完成
    while (this.isUpdating) {
      await new Promise(resolve => setTimeout(resolve, 50));
    }
    
    this.isUpdating = true;
    
    try {
      // 执行更新操作
      await this.performUpdate(newData);
    } finally {
      this.isUpdating = false;
    }
  }
  
  private async performUpdate(data: any): Promise<void> {
    // 实际更新逻辑
  }
}

问题4: 状态数据过大导致性能问题

现象: 状态数据太多导致UI渲染变慢

解决方案:

typescript 复制代码
// 使用状态切片
class SlicedStore {
  // 用户状态
  private userSlice = new UserSlice();
  
  // 学习状态
  private learningSlice = new LearningSlice();
  
  // 获取状态切片
  getUserSlice(): UserSlice {
    return this.userSlice;
  }
  
  getLearningSlice(): LearningSlice {
    return this.learningSlice;
  }
}

class UserSlice {
  private user: User | null = null;
  private listeners: Set<() => void> = new Set();
  
  setUser(user: User | null): void {
    this.user = user;
    this.notify();
  }
  
  getUser(): User | null {
    return this.user;
  }
  
  subscribe(listener: () => void): () => void {
    this.listeners.add(listener);
    return () => this.listeners.delete(listener);
  }
  
  private notify(): void {
    this.listeners.forEach(listener => listener());
  }
}

class LearningSlice {
  private stats: LearningStats = { totalDays: 0, score: 0 };
  private listeners: Set<() => void> = new Set();
  
  updateStats(stats: Partial<LearningStats>): void {
    this.stats = { ...this.stats, ...stats };
    this.notify();
  }
  
  getStats(): LearningStats {
    return { ...this.stats };
  }
  
  subscribe(listener: () => void): () => void {
    this.listeners.add(listener);
    return () => this.listeners.delete(listener);
  }
  
  private notify(): void {
    this.listeners.forEach(listener => listener());
  }
}

interface LearningStats {
  totalDays: number;
  score: number;
}

interface User {
  id: string;
  name: string;
}

性能优化策略

策略1: 状态懒加载

typescript 复制代码
// 只在需要时加载状态
class LazyStore {
  private data: any = null;
  private isLoaded: boolean = false;
  
  async getData(): Promise<any> {
    if (this.isLoaded) {
      return this.data;
    }
    
    // 懒加载数据
    this.data = await this.loadData();
    this.isLoaded = true;
    
    return this.data;
  }
  
  private async loadData(): Promise<any> {
    // 从API或存储加载数据
    return {};
  }
  
  // 重置加载状态
  reset(): void {
    this.isLoaded = false;
    this.data = null;
  }
}

策略2: 状态变更防抖

typescript 复制代码
// 合并频繁的状态更新
class DebouncedStore {
  private debounceTimer: number | null = null;
  private pendingUpdates: Array<() => void> = [];
  
  scheduleUpdate(update: () => void): void {
    this.pendingUpdates.push(update);
    
    if (this.debounceTimer) {
      clearTimeout(this.debounceTimer);
    }
    
    this.debounceTimer = setTimeout(() => {
      this.applyUpdates();
    }, 100); // 100ms防抖
  }
  
  private applyUpdates(): void {
    // 批量应用所有待更新
    this.pendingUpdates.forEach(update => update());
    this.pendingUpdates = [];
    this.debounceTimer = null;
  }
}

本章小结

核心知识点

本文完成了状态管理实战的深度学习:

1. 状态管理方案对比

  • ArkTS内置状态 vs 全局Store vs 事件总线
  • 方案选型建议

2. 组件状态管理

  • @State、@Prop、@Link、@Computed的正确使用
  • 状态更新的正确方式(不可变性)

3. 全局状态管理

  • 单例模式实现
  • 订阅/通知机制
  • 状态切片设计

4. 实际应用场景

  • 用户认证状态管理
  • 购物车状态管理

5. 常见问题解决方案

  • 状态更新不触发UI刷新
  • 订阅导致内存泄漏
  • 异步操作导致状态不一致
  • 状态数据过大

6. 性能优化策略

  • 状态懒加载
  • 状态变更防抖

下一步预告

状态管理实战已经完成!在下一篇文章中,我们将学习:

  • 数据模型设计
  • 数据结构定义
  • 数据验证
  • 数据转换

相关链接

相关推荐
YM52e2 小时前
买菜计算器小应用 - HarmonyOS ArkUI 开发实战-PC版本
学习·华为·harmonyos·鸿蒙·鸿蒙系统
阿捏利2 小时前
系列总览-鸿蒙科普系列完全指南
华为·harmonyos
小雨下雨的雨2 小时前
HarmonyOS ArkUI训练营入门-组件掌握系列-Animation 动画效果实现-PC版本
学习·华为·harmonyos·鸿蒙
yuegu7772 小时前
HarmonyOS应用<节气通>开发第32篇:ArkTS语法快速入门——从TypeScript到声明式UI的完整指南
harmonyos
2601_962072554 小时前
李梦娇常识4600问|题库|打印版
sql·华为od·华为·c#·华为云·.net·harmonyos
伶俜664 小时前
鸿蒙原生应用实战(十九)ArkUI 喝水提醒 App:定时通知 + 每日记录 + 统计图表
华为·harmonyos
风华圆舞4 小时前
Flutter + 鸿蒙 Intents Kit:页面直达能力的完整接入方案
flutter·ui·华为·harmonyos
三声三视5 小时前
Electron 在鸿蒙 PC 上跑 webview,我是怎么把首屏从 4.2s 干到 1.1s 的
华为·electron·harmonyos·鸿蒙
互联网散修6 小时前
鸿蒙实战:从0到1构建功能完备的搜索页面
华为·harmonyos