Appearance
复杂状态管理方案
在大型项目中,单一装饰器不够用,需要组合多种状态管理方案。
1. 状态管理方案选择决策树
需要管理状态吗?
├─ 否 → 不需要
├─ 组件内部私有?
│ ├─ 是 → @State
│ └─ 否
│ ├─ 父→子单向?
│ │ ├─ 简单类型 → @Prop
│ │ └─ 复杂对象 → @Link
│ ├─ 父↔子双向?
│ │ └─ → @Link
│ ├─ 跨树共享?
│ │ └─ → @Provide/@Consume
│ ├─ 全局配置?
│ │ └─ → AppStorage
│ ├─ 页面级存储?
│ │ └─ → LocalStorage
│ ├─ 嵌套对象深度监听?
│ │ ├─ V2 → @Trace
│ │ └─ V1 → @Observed + @ObjectLink
│ └─ 状态变化需执行副作用?
│ └─ → @Watch
└─ 需要持久化?
└─ → PersistentStorage2. 混合方案实践
2.1 大型应用状态架构
应用架构
├── AppStorage(全局)
│ ├── currentUser(用户信息)
│ ├── theme(主题)
│ └── language(语言)
│
├── UIAbility 级(LocalStorage)
│ ├── pageState(页面状态)
│ └── navigationHistory(导航历史)
│
├── 页面级(@State)
│ ├── listData(列表数据)
│ ├── filterOptions(筛选条件)
│ └── loadingState(加载状态)
│
└── 组件级(@State)
├── isOpen(弹窗状态)
├── selectedId(选中项)
└── inputText(输入内容)2.2 实际示例:新闻阅读应用
typescript
// ============ 全局状态 ============
// App.ts
@Entry
@Component
struct App {
@Provide currentUser: UserInfo = { name: '游客', avatar: $r('app.media.default') }
@Provide theme: ThemeType = ThemeType.Light
@Provide language: Language = Language.zh
build() {
Column() {
Navigation()
}
}
}
// ============ 页面级状态 ============
// pages/NewsList.ts
@Entry
@Component
struct NewsList {
@State articles: Article[] = []
@State page: number = 1
@State loading: boolean = false
@State hasMore: boolean = true
@State selectedCategory: string = 'all'
aboutToAppear() {
this.loadArticles()
}
async loadArticles() {
this.loading = true
const response = await http.get(`/api/news?page=${this.page}&category=${this.selectedCategory}`)
this.articles = response.data
this.loading = false
}
build() {
Column() {
CategoryBar({ category: this.selectedCategory })
NewsGrid({ articles: this.articles, loading: this.loading })
LoadMore({ hasMore: this.hasMore, onLoadMore: () => this.loadMore() })
}
}
loadMore() {
this.page++
this.loadArticles()
}
}
// ============ 组件级状态 ============
// components/NewsCard.ts
@Component
struct NewsCard {
@Prop article: Article
@State isFavorite: boolean = false
@State isExpanded: boolean = false
build() {
Column() {
Image(this.article.cover)
.width('100%')
.height(this.isExpanded ? 'auto' : 150)
Text(this.article.title)
.fontSize(16fp)
.fontWeight(FontWeight.Bold)
if (this.isExpanded) {
Text(this.article.summary)
.fontSize(14fp)
}
}
.borderRadius(8)
.onClick(() => {
this.isExpanded = !this.isExpanded
})
.onLongClick(() => {
this.isFavorite = !this.isFavorite
})
}
}3. 状态管理方案速查表
| 场景 | 推荐方案 | 代码示例 |
|---|---|---|
| 组件内部 | @State | @State count: number = 0 |
| 父子单向 | @Prop | @Prop name: string |
| 父子双向 | @Link | @Link value: number |
| 跨树 | @Provide/@Consume | @Provide / @Consume |
| 全局 | AppStorage | AppStorage.setOrCreate() |
| 页面级 | LocalStorage | new LocalStorage() |
| 深度监听 | @Trace(V2) / @ObjectLink(V1) | @Trace data: UserData |
| 变化回调 | @Watch | @Watch('onChange') |
| 持久化 | PersistentStorage | new PersistentStorage() |
4. 常见组合模式
4.1 状态提升模式
typescript
// 子组件状态提升到父组件
@Component
struct SearchInput {
@Prop value: string
@Event onSearch: (keyword: string) => void
build() {
TextInput({ placeholder: '搜索' })
.onChange((v: string) => {
this.onSearch(v)
})
}
}
@Entry
@Component
struct SearchPage {
@State keyword: string = '' // 状态提升到父组件
build() {
SearchInput({
value: this.keyword,
onSearch: (kw: string) => {
this.keyword = kw // 搜索
this.doSearch(kw)
}
})
}
}4.2 Store 模式
typescript
// store/NewsStore.ts
class NewsStore {
articles: Article[] = []
loading: boolean = false
page: number = 1
async fetchArticles() {
this.loading = true
const res = await http.get('/api/news')
this.articles = res.data
this.loading = false
}
}
export default new NewsStore()
// 页面使用
@Entry
@Component
struct Index {
@State store: NewsStore = NewsStore.getInstance()
aboutToAppear() {
this.store.fetchArticles()
}
build() {
NewsList({ articles: this.store.articles })
}
}5. 面试高频考点
Q1: 如何选择状态管理方案?
回答:组件内部用 @State,父子单向用 @Prop,父子双向用 @Link,跨树用 @Provide/@Consume,全局用 AppStorage,深度监听用 @Trace(V2)。
Q2: 状态提升是什么?
回答:将子组件的状态提升到父组件,通过 @Link 双向绑定。适用于需要父组件响应子组件状态变化的场景。
Q3: 复杂的混合状态管理方案有哪些?
回答:AppStorage(全局)+ LocalStorage(页面)+ @State(组件)的组合使用。根据数据的作用域和生命周期选择合适的方案。
🐱 小猫提示:状态管理选型记住:"看作用域,选对应方案"。组件内→@State,父子→@Link,跨树→@Provide/@Consume,全局→AppStorage。