Skip to content

复杂状态管理方案

在大型项目中,单一装饰器不够用,需要组合多种状态管理方案。


1. 状态管理方案选择决策树

需要管理状态吗?
├─ 否 → 不需要
├─ 组件内部私有?
│   ├─ 是 → @State
│   └─ 否
│       ├─ 父→子单向?
│       │   ├─ 简单类型 → @Prop
│       │   └─ 复杂对象 → @Link
│       ├─ 父↔子双向?
│       │   └─ → @Link
│       ├─ 跨树共享?
│       │   └─ → @Provide/@Consume
│       ├─ 全局配置?
│       │   └─ → AppStorage
│       ├─ 页面级存储?
│       │   └─ → LocalStorage
│       ├─ 嵌套对象深度监听?
│       │   ├─ V2 → @Trace
│       │   └─ V1 → @Observed + @ObjectLink
│       └─ 状态变化需执行副作用?
│           └─ → @Watch
└─ 需要持久化?
    └─ → PersistentStorage

2. 混合方案实践

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
全局AppStorageAppStorage.setOrCreate()
页面级LocalStoragenew LocalStorage()
深度监听@Trace(V2) / @ObjectLink(V1)@Trace data: UserData
变化回调@Watch@Watch('onChange')
持久化PersistentStoragenew 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。