上篇文章中,介绍了各个状态管理的详细定义与使用方法;这篇简单介绍下它们大多会用到哪些地方;以及使用它们时应该注意什么:
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 显示旧数据或出现闪烁现象。需要在异步操作完成后正确更新状态,并考虑使用加载提示来改善用户体验。
通过避免这些常见的误区,开发者可以更有效地进行状态管理,提升应用的性能和用户体验。
898

被折叠的 条评论
为什么被折叠?



