鸿蒙开发中状态管理有哪些常见的应用场景?

        上篇文章中,介绍了各个状态管理的详细定义与使用方法;这篇简单介绍下它们大多会用到哪些地方;以及使用它们时应该注意什么:

1. 组件内的状态管理

  • @State 装饰器:适用于需要在同一组件中管理并展示的状态,如表单输入、按钮状态等。当状态变化时,组件会自动重新渲染。
  • 示例:在一个计数器组件中,使用 @State 装饰器来管理计数器的值,当用户点击标签时,参数 age的值会增加并自动更新UI。
  • struct Index {
      @State name:string='东林'
      @State age:number=18
      build() {
        Column(){
          Text(`${this.name}:${this.age}`)
            .width(100)
            .height(50)
            .onClick(()=>{
              this.age++
            })
    
        }.width('100%').height('100%')
      }
    }

2. 父子组件状态共享

  • @Provide / @Consume 装饰器:用于在父子组件之间共享状态。父组件通过 @Provide 提供状态,子组件通过 @Consume 消费状态。
  • @Link / @Prop 装饰器@Link 支持双向绑定,@Prop 支持单向绑定。适用于需要在父子组件之间传递和修改状态的场景。
  • 示例:在一个父组件中,使用 @Provide 提供一个消息字符串,子组件通过 @Consume 获取并显示该消息。
  • // 定义一个简单的服务类
    interface GeneratedObjectLiteralInterface_1 {
      name: string;
      age: number;
    }
    
    class UserService {
      getUserInfo() {
        return ({
          name: "张三",
          age: 18
        } as GeneratedObjectLiteralInterface_1);
      }
    }
    
    // 定义父组件
    @Entry
    @Component
    struct Index {
      // 使用 @Provide 装饰器提供 UserService 实例
      @Provide userService: UserService = new UserService();
    
      build() {
        Column() {
          Text("Parent 组件").fontSize(20).margin(20);
          // 使用子组件
          ChildComponent();
        }
      }
    }
    
    // 定义子组件
    @Component
    struct ChildComponent {
      // 使用 @Consume 装饰器消费 UserService 实例
      @Consume userService!: UserService;
    
      build() {
        Column() {
          Text("Child 组件").fontSize(20).margin(20);
          Text(`姓名:${this.userService.getUserInfo().name}`).fontSize(16).margin(10);
          Text(`年龄:${this.userService.getUserInfo().age}`).fontSize(16).margin(10);
        }
      }
    }

    如果需要子组件能够修改消息,可以使用 @Link 实现双向绑定。

  • // 定义一个简单的服务类
    
    interface Person {
      name: string;
      age: number;
    }
    
    class UserService {
      private user: Person = { name: "张三", age: 18 };
    
      getUserInfo() {
        return this.user;
      }
    }
    
    // 定义父组件
    @Entry
    @Component
    struct Index {
      @Provide userService: UserService = new UserService();
      @State age: number = this.userService.getUserInfo().age;
      @State name: string = this.userService.getUserInfo().name;
    
      build() {
        Column() {
          Text("Parent 组件").fontSize(20).margin(20);
          ChildComponent({ age: $age ,name: $name});
        }
      }
    }
    
    // 定义子组件
    @Component
    struct ChildComponent {
      @Link age!: number;
      @Link name!: number;
    
      build() {
        Column() {
          Text("Child 组件").fontSize(20).margin(20);
          Text(`姓名:${this.name}`).fontSize(16).margin(10);
          Text(`年龄:${this.age}`).fontSize(16).margin(10);
          Button("增加年龄")
            .margin(10)
            .onClick(() => {
              this.age += 1;
            });
        }
      }
    }
    

3. 全局状态共享

  • @ProvideGlobal / @ConsumeGlobal 装饰器:用于在应用的全局范围内共享状态,所有的组件都可以访问和修改这些状态。
  • 示例:在一个多页面应用中,使用 @ProvideGlobal 提供一个主题状态(如亮色或暗色主题),所有页面都可以通过 @ConsumeGlobal 访问并根据主题更新UI。
  • // 定义全局主题服务
    @ProvideGlobal
    class ThemeService {
      @State theme: string = "light"; // 默认亮色主题
    
      toggleTheme() {
        this.theme = this.theme === "light" ? "dark" : "light";
      }
    }
    
    // 主页组件
    @Entry
    @Component
    struct HomePage {
      build() {
        Column() {
          Text("主页").fontSize(24).margin(20);
          ThemeSwitcher(); // 主题切换组件
          NavigateButton("跳转到设置页", SettingsPage);
        }
      }
    }
    
    // 设置页组件
    @Component
    struct SettingsPage {
      @ConsumeGlobal themeService!: ThemeService;
    
      build() {
        Column() {
          Text("设置页").fontSize(24).margin(20);
          Text(`当前主题:${this.themeService.theme}`).fontSize(18).margin(10);
          ThemeSwitcher(); // 复用主题切换组件
          NavigateButton("返回主页", HomePage);
        }
      }
    }
    
    // 主题切换组件å
    @Component
    struct ThemeSwitcher {
      @ConsumeGlobal themeService!: ThemeService;
    
      build() {
        Column() {
          Button(`切换主题(当前:${this.themeService.theme})`)
            .margin(10)
            .onClick(() => {
              this.themeService.toggleTheme();
            });
        }
      }
    }
    
    // 导航按钮组件
    @Component
    struct NavigateButton {
      private label: string;
      private target: any;
    
      constructor(label: string, target: any) {
        this.label = label;
        this.target = target;
      }
    
      build() {
        Button(this.label)
          .margin(10)
          .onClick(() => {
            Router.push(this.target);
          });
      }
    }
    

4. 持久化状态管理

  • LocalStorage:适用于页面级的内存存储,生命周期与页面绑定,适合临时状态和页面间通信。
  • AppStorage:适用于应用级的全局状态管理,支持跨Ability/页面共享,适合全局配置读取和用户登录状态管理等。
  • PersistentStorage:适用于需要持久化的状态,如用户偏好设置和离线缓存,数据在应用重启后仍然存在。
  • 示例:在一个设置页面中,使用 PersistentStorage 存储用户的字体大小设置,当用户更改设置时,数据会被持久化,下次打开应用时仍然有效。
// 导入持久化存储模块
import { PersistentStorage } from '@system.storage';

// 定义全局字体设置服务
@ProvideGlobal
class FontSizeService {
  @State fontSize: number = 16; // 默认字体大小

  constructor() {
    this.loadFontSize();
  }

  async loadFontSize() {
    let storedSize = await PersistentStorage.get('fontSize');
    if (storedSize) {
      this.fontSize = parseInt(storedSize);
    }
  }

  async setFontSize(size: number) {
    this.fontSize = size;
    await PersistentStorage.set('fontSize', size.toString());
  }
}

// 主页组件
@Entry
@Component
struct HomePage {
  build() {
    Column() {
      Text("主页").fontSize(24).margin(20);
      NavigateButton("跳转到设置页", SettingsPage);
    }
  }
}

// 设置页组件
@Component
struct SettingsPage {
  @ConsumeGlobal fontSizeService!: FontSizeService;

  build() {
    Column() {
      Text("设置页").fontSize(24).margin(20);
      Text(`当前字体大小:${this.fontSizeService.fontSize}`).fontSize(this.fontSizeService.fontSize).margin(10);
      Row() {
        Button("增加字体大小")
          .margin(10)
          .onClick(() => {
            this.fontSizeService.setFontSize(this.fontSizeService.fontSize + 2);
          });
        Button("减小字体大小")
          .margin(10)
          .onClick(() => {
            this.fontSizeService.setFontSize(this.fontSizeService.fontSize - 2);
          });
      }
      NavigateButton("返回主页", HomePage);
    }
  }
}

// 导航按钮组件
@Component
struct NavigateButton {
  private label: string;
  private target: any;

  constructor(label: string, target: any) {
    this.label = label;
    this.target = target;
  }

  build() {
    Button(this.label)
      .margin(10)
      .onClick(() => {
        Router.push(this.target);
      });
  }
}

注:鸿蒙开发中状态管理有哪些常见的误区?

在鸿蒙开发中,状态管理是一个关键但复杂的环节。开发者在进行状态管理时,可能会遇到一些常见的误区,以下是一些典型的例子:

1.过度使用全局状态:

开发者可能会过度依赖全局状态管理工具(如 AppStorage 或 Provide/Consume),导致状态管理变得复杂且难以维护。过多的全局状态会使代码耦合度增加,难以追踪状态的变化。


2.忽视状态更新的效率:

在使用 @State 装饰器时,开发者需要注意并不是所有的状态变化都会引起 UI 的刷新。只有可以被框架观察到的修改才会触发 UI 更新。例如,对象的嵌套属性变化或数组元素内部属性的变化可能不会被检测到,导致 UI 不更新。


3.不恰当的线程安全处理:

鸿蒙 OS 的多线程环境中,多个线程同时访问共享资源时可能会引发数据不一致或竞态条件。开发者需要使用互斥锁等机制来确保线程安全,但有时可能会忽略这一点,导致应用出现异常。


4.忽略生命周期管理:

在使用持久化存储(如 PersistentStorage)时,开发者需要特别注意对象的生命周期管理,确保在适当的时机释放不再需要的资源,防止内存泄漏。


5.错误的状态同步方式:

在父子组件之间传递状态时,开发者可能会错误地使用 @Prop 装饰器进行双向同步,而实际上应该使用 @Link 装饰器来实现双向绑定。反之亦然,误用 @Link 导致不必要的父组件状态更新。


6.缺乏状态管理的最佳实践:

开发者可能没有遵循状态管理的最佳实践,例如,未能合理划分状态的粒度,导致状态管理混乱。或者未能充分利用 ArkTS 提供的装饰器和工具,使得状态管理变得繁琐。


7.忽视异步操作对状态的影响:

在处理异步操作(如网络请求)时,开发者可能会忽略状态更新的时机,导致 UI 显示旧数据或出现闪烁现象。需要在异步操作完成后正确更新状态,并考虑使用加载提示来改善用户体验。


通过避免这些常见的误区,开发者可以更有效地进行状态管理,提升应用的性能和用户体验。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值