【OpenHarmony/HarmonyOs 】ArkTS 项目中的状态管理:@State、@Link、LocalStorage 实战

ArkUI 开发中,状态管理是最容易出问题的地方之一。页面为什么不刷新?父子组件为什么不同步?深色模式为什么切了但颜色没变?本文结合 政治视界 项目,系统整理 @State@Link@PropLocalStorage 在真实项目中的用法 ⚙️

一、状态管理的基本分层

项目中状态大致分为四类:

  • 页面内部状态:按钮按压、弹窗显示、当前索引;
  • 父子共享状态:当前 Tab、首页刷新信号;
  • 全局状态:安全区、深色模式;
  • 持久化业务状态:错题、学习统计、设置。

不同状态要用不同工具,不要所有东西都塞进一个全局对象。

二、@State:页面内部响应式状态

题库页面中:

@State currentQuestionIndex: number = 0;
@State selectedAnswer: string[] = [];
@State showResult: boolean = false;
@State isCorrect: boolean = false;

这些状态只属于 QuizPage,所以用 @State 最合适。用户选择答案后,selectedAnswer 变化,选项 UI 自动更新;提交后 showResult 变化,结果区域显示。

三、@Link:父子组件双向绑定

首页需要修改当前 Tab,从推荐题跳到题库。因此 HomePage 接收父组件传入的 currentTab

@Component
export struct HomePage {
  @Link currentTab: number;
}

父组件中这样传入:

HomePage({ currentTab: $currentTab, refreshSignal: $homePageRefresh })

首页点击推荐题:

goToPractice(questionId: number): void {
  this.dataManager.setQuizJumpQuestion(questionId);
  this.currentTab = 3;
}

@Link 适合这种父子之间需要双向同步的场景。

四、@Prop:单向传值

有些子组件只需要接收值,不需要修改父组件状态,就用 @Prop。例如统计页中的分类统计行:

@Component
struct CategoryStatItem {
  @Prop category: string = '';
  @Prop total: number = 0;
  @Prop correct: number = 0;
}

注意项目规范里也强调:@Prop 不要写可选参数,给默认值更稳。

五、LocalStorage:全局轻量状态

安全区和深色模式属于全局状态。项目中创建了 appLocalStorage

const storage: LocalStorage = new LocalStorage();
storage.setOrCreate(SAFE_AREA_TOP_VP_KEY, 0);
storage.setOrCreate(SAFE_AREA_BOTTOM_VP_KEY, 0);
storage.setOrCreate(STORAGE_KEY_DARK_MODE, false);

页面通过:

@LocalStorageProp(SAFE_AREA_TOP_VP_KEY) safeTopVp: number = 0;
@LocalStorageProp(SAFE_AREA_BOTTOM_VP_KEY) safeBottomVp: number = 0;

读取安全区高度。这让所有页面都能共享窗口避让区数据。

六、@LocalStorageLink:全局状态双向更新

主题刷新令牌使用:

@LocalStorageLink(THEME_REFRESH_KEY)
private themeRefresh: number = 0;

切换主题时:

this.themeRefresh = this.themeRefresh + 1;

它不仅修改本页面状态,也更新 LocalStorage 中的值,从而让其他绑定者感知变化。

七、@Watch:监听状态变化

主页面监听深色模式变化:

@Watch('onDarkModeChange')
@LocalStorageProp(DARK_MODE_KEY) isDarkMode: boolean = false;

onDarkModeChange(): void {
  AppTheme.isDarkMode = this.isDarkMode;
  AppTheme.themeRefreshToken = this.themeRefresh;
}

@Watch 很适合做“状态变化后的副作用”,比如同步主题管理器。

八、持久化状态不要直接放 UI

错题、学习统计、设置这些数据最终要保存到 Preferences,所以项目通过 DataManager 管理:

private dataManager: DataManager = DataManager.getInstance();

initStats(): void {
  this.completedQuestions = this.dataManager.getCompletedQuestions();
  this.correctRate = this.dataManager.getCorrectRate();
}

页面只把读取结果放入 @State 展示,不直接操作 Preferences。

九、常见坑

  1. 修改普通变量不会触发 UI 更新;
  2. 静态变量变化不一定触发页面刷新;
  3. 子组件要修改父组件状态时必须用 @Link
  4. 列表数据变化最好赋新数组;
  5. 复杂逻辑不要写在 build() 里;
  6. ForEach 要提供稳定 key。

十、结语

政治视界中状态管理比较清晰:页面状态用 @State,父子同步用 @Link,只读传值用 @Prop,安全区和主题用 LocalStorage,业务持久化交给 DataManager

ArkUI 状态管理的核心不是记住所有装饰器,而是判断“这个状态属于谁、谁会修改、是否需要持久化”。这个问题想清楚了,页面就会稳定很多 ✅

img

img

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐