跨平台状态管理:React / Next.js / Flutter / Swift / RxSwift / SwiftUI / ArkTS / RxJava / Agera / Jetpack Compose

由浅入深,从基本概念到源码原理,再到实战案例,系统梳理 Web、移动、原生各平台的状态管理方案


一、什么是状态管理?

1.1 状态(State)的本质

状态是应用在某一时刻的数据快照,它决定了 UI 的展示内容和行为。任何会随时间变化的数据——用户输入、网络请求结果、权限、主题——都可视为状态。

1
2
3
4
5
6
7
8
9
+------------+   +------------+   +------------+   +------------+
| User Input | | Biz Data | | UI State | | Server |
| Form/Search| | List/Detail| |Modal/Load | | Cache |
+------+-----+ +------+-----+ +------+-----+ +------+-----+
| | | |
+-----------------+--------+--------+-----------------+
|
v
UI 渲染 / 副作用执行

用户输入·业务数据·UI状态·服务端 → 汇聚为统一的 UI 渲染与副作用执行

1.2 为什么需要状态管理?

痛点 说明 状态管理的价值
散落 状态分散在各处,难以追踪 集中、可预测的数据流
同步 多处 UI 依赖同一数据,容易不一致 单一数据源(Single Source of Truth)
生命周期 状态何时创建、何时销毁、何时持久化 与组件/页面生命周期绑定
跨层级 深层级组件需要访问顶层状态 提供 Context / Provider / 依赖注入
可测试 业务逻辑与 UI 耦合,难以单测 状态逻辑可独立测试

1.3 各平台状态管理方案概览

平台/框架 主要方案 核心机制 特点
React Hooks (useState/useReducer) 虚拟 DOM diff + 依赖收集 函数式、声明式、生态丰富
Next.js Server Components + Client State 服务端/客户端分离 减少客户端 JS、流式渲染
Flutter Provider / Riverpod / Bloc InheritedWidget / Listenable Dart 异步流、可组合
Swift Combine / 手动 KVO 发布-订阅 系统级、与 SwiftUI 整合
RxSwift Observable / Subject 响应式流 操作符丰富、事件驱动
SwiftUI @State / @Binding / @Observable 声明式 + 属性包装器 数据驱动视图、自动重绘
ArkTS @State / @Prop / @Link 装饰器 + 响应式 鸿蒙声明式 UI
RxJava Observable / Subject 响应式流 异步编排、背压支持
Agera Observable / Updatable 推事件-拉数据 Google 早期方案,已归档
Jetpack Compose remember / mutableStateOf 重组(Recomposition) 声明式、与 Kotlin 协程整合

二、状态管理的核心原则与模式

2.1 单向数据流(Unidirectional Data Flow)

大多数现代框架采用「单向数据流」:状态向下流动,事件向上反馈。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
┌─────────────┐
│ State │ ← 单一数据源
└──────┬──────┘
│ 只读传递

┌─────────────┐
│ View │ → 用户操作
└──────┬──────┘
│ 事件 / Action

┌─────────────┐
│ Reducer / │ → 计算新状态
│ setState │
└──────┬──────┘

└──────────► 更新 State → 重新渲染

React、Redux、Flutter Bloc、Jetpack Compose 的 ViewModel 均遵循此模式。

2.2 观察者模式:统一的底层基石

状态管理大多基于观察者模式:被观察对象变化时,通知所有订阅者。

平台 被观察者 观察者 通知方式
React useState 返回值 组件函数 调度重渲染
SwiftUI @State / @Published 视图 body 自动重算 body
Jetpack Compose mutableStateOf Composable 重组(Recomposition)
Flutter ChangeNotifier addListener notifyListeners
RxJava Observable Observer onNext
ArkTS @State 变量 组件 build 框架触发重绘

2.3 局部状态 vs 全局状态

类型 范围 典型方案 场景
局部状态 单组件/单页面 useState / @State / remember 输入框、折叠面板、动画
共享状态 多组件/跨页面 Context / Provider / ViewModel 主题、用户信息、购物车
服务端状态 与后端同步 React Query / SWR / 自定义 列表、详情、缓存

三、Web 前端:React 与 Next.js

3.1 React 状态管理

3.1.1 基本概念:useState

useState 是 React 最基础的状态 Hook,返回当前值和更新函数:

1
2
3
4
5
6
7
8
function Counter() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(c => c + 1)}>
Count: {count}
</button>
);
}

原理简述:React 在内部维护 Fiber 树,每个组件对应一个 Fiber 节点,useState 将状态存储在 Fiber 的 memoizedState 链表中。更新时调度 setState,标记组件需要重渲染,之后执行 diff 并提交 DOM 变更。

3.1.2 派生状态与 useReducer

当状态逻辑复杂时,用 useReducer 集中处理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function reducer(state, action) {
switch (action.type) {
case 'increment': return { count: state.count + 1 };
case 'decrement': return { count: state.count - 1 };
default: return state;
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, { count: 0 });
return (
<>
<span>{state.count}</span>
<button onClick={() => dispatch({ type: 'increment' })}>+</button>
</>
);
}

3.1.3 跨组件共享:Context

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const ThemeContext = createContext('light');

function App() {
const [theme, setTheme] = useState('light');
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
<Header />
<Main />
</ThemeContext.Provider>
);
}

function Header() {
const { theme } = useContext(ThemeContext);
return <div className={theme}>...</div>;
}

注意:Context 变化会导致所有消费该 Context 的组件重渲染,可配合 useMemo / 拆分 Provider 优化。

3.1.4 副作用与依赖:useEffect

1
2
3
4
5
6
7
8
9
10
const [keyword, setKeyword] = useState('');
const [users, setUsers] = useState([]);

useEffect(() => {
if (keyword.length < 2) return;
const timer = setTimeout(() => {
fetchUsers(keyword).then(setUsers);
}, 300);
return () => clearTimeout(timer); // 清理函数
}, [keyword]);

3.2 Next.js 状态管理

Next.js 引入 Server ComponentsClient Components 的区分,状态管理策略随之变化。

3.2.1 服务端 vs 客户端状态

类型 组件 可用能力 典型场景
Server Component 默认 直接 fetch、访问 DB、无 hooks 静态内容、SEO、首屏数据
Client Component 'use client' useState、useEffect、事件处理 交互、表单、实时更新

3.2.2 组合模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// app/page.tsx - Server Component(默认)
async function Page() {
const data = await fetchFromDB(); // 服务端直接拉取
return (
<Layout>
<StaticContent data={data} />
<InteractiveCart /> {/* Client Component,内部用 useState */}
</Layout>
);
}

// components/InteractiveCart.tsx
'use client';
export function InteractiveCart() {
const [items, setItems] = useState([]);
return <CartUI items={items} onAdd={...} />;
}

3.2.3 Context 在 Next.js 中的使用

Context Provider 必须放在 Client Component 中:

1
2
3
4
5
6
7
8
9
10
// providers/ThemeProvider.tsx
'use client';
export function ThemeProvider({ children }) {
const [theme, setTheme] = useState('light');
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
{children}
</ThemeContext.Provider>
);
}

四、跨平台移动:Flutter

4.1 基本概念

Flutter 的 UI 是声明式的:给定状态,构建对应 Widget 树。状态变化触发 setStatenotifyListeners,进而重建 Widget。

4.2 内置方案

4.2.1 StatefulWidget + setState

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Counter extends StatefulWidget {
@override
_CounterState createState() => _CounterState();
}

class _CounterState extends State<Counter> {
int _count = 0;
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () => setState(() => _count++),
child: Text('$_count'),
);
}
}

4.2.2 ValueNotifier + ValueListenableBuilder(局部重建)

1
2
3
4
5
6
7
final counter = ValueNotifier<int>(0);

ValueListenableBuilder<int>(
valueListenable: counter,
builder: (context, value, child) => Text('$value'),
)
// 只有 ValueListenableBuilder 会重建,而非整棵子树

4.2.3 ChangeNotifier + Provider

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class CartModel extends ChangeNotifier {
final List<Item> _items = [];
void add(Item item) {
_items.add(item);
notifyListeners();
}
}

// 根节点
ChangeNotifierProvider(create: (_) => CartModel(), child: MyApp())

// 子节点消费
context.watch<CartModel>(); // 监听变化并重建
context.read<CartModel>(); // 仅读取,不监听

4.3 进阶:Riverpod / Bloc

  • Riverpod:编译期安全、可测试、不依赖 BuildContext
  • Bloc:事件 → 状态 的显式映射,适合复杂业务流

五、iOS 原生:Swift、RxSwift、SwiftUI

5.1 Swift 传统方式

  • 属性观察器willSet / didSet
  • KVOobserve(_:options:changeHandler:)
  • 通知NotificationCenter
  • Delegate / 闭包回调

5.2 RxSwift 响应式状态

RxSwift 将状态抽象为,通过 Observable / Subject 管理:

1
2
3
4
5
6
7
8
9
10
11
// 文本框输入 → 搜索
let searchResults = searchTextField.rx.text.orEmpty
.debounce(.milliseconds(300), scheduler: MainScheduler.instance)
.flatMapLatest { api.search($0) }
.observe(on: MainScheduler.instance)

searchResults
.bind(to: tableView.rx.items(cellIdentifier: "Cell")) { _, model, cell in
cell.textLabel?.text = model.name
}
.disposed(by: disposeBag)

Subject 可同时作为观察者和被观察者,常用于「桥接」命令式代码与响应式流:

1
2
3
4
5
6
7
8
let buttonTaps = PublishSubject<Void>()
buttonTaps
.flatMapLatest { api.fetchData() }
.subscribe(onNext: { updateUI($0) })
.disposed(by: disposeBag)

// 命令式触发
button.rx.tap.bind(to: buttonTaps).disposed(by: disposeBag)

5.3 SwiftUI 声明式状态

5.3.1 @State:组件内部值类型状态

1
2
3
4
5
6
struct CounterView: View {
@State private var count = 0
var body: some View {
Button("Count: \(count)") { count += 1 }
}
}

5.3.2 @Binding:父子双向绑定

1
2
3
4
5
6
7
8
9
10
11
12
13
struct ParentView: View {
@State private var isOn = false
var body: some View {
ToggleView(isOn: $isOn) // 传递 Binding
}
}

struct ToggleView: View {
@Binding var isOn: Bool
var body: some View {
Toggle("", isOn: $isOn)
}
}

5.3.3 @ObservedObject / @StateObject:引用类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class UserViewModel: ObservableObject {
@Published var name = ""
@Published var isLoading = false
}

struct ProfileView: View {
@StateObject private var viewModel = UserViewModel() // 创建并持有
var body: some View {
Text(viewModel.name)
}
}

struct ChildView: View {
@ObservedObject var viewModel: UserViewModel // 从父组件传入
var body: some View { ... }
}

5.3.4 @Observable(iOS 17+)

新宏 @Observable 可替代 ObservableObject,更简洁:

1
2
3
4
5
6
7
8
9
10
11
12
@Observable
class User {
var name: String = ""
var age: Int = 0
}

struct UserView: View {
@State private var user = User()
var body: some View {
Text(user.name) // 自动追踪依赖
}
}

六、Android 原生:RxJava、Agera、Jetpack Compose

6.1 RxJava 响应式状态

1
2
3
4
5
6
7
8
9
val querySubject = PublishSubject.create<String>()
val results = querySubject
.debounce(300, TimeUnit.MILLISECONDS)
.filter { it.length >= 2 }
.switchMap { api.search(it).toObservable() }
.observeOn(AndroidSchedulers.mainThread())

results.subscribe { updateUI(it) }.addTo(compositeDisposable)
querySubject.onNext(editText.text.toString())

StateFlow / SharedFlow(Kotlin Flow)是官方推荐替代 LiveData 的方案:

1
2
3
4
5
6
7
8
9
10
class ViewModel : ViewModel() {
private val _uiState = MutableStateFlow<UiState>(UiState.Loading)
val uiState: StateFlow<UiState> = _uiState.asStateFlow()

fun loadData() {
viewModelScope.launch {
_uiState.value = UiState.Success(repository.fetch())
}
}
}

6.2 Agera 简介(已归档)

Agera 是 Google 早期的轻量级响应式库,采用推事件、拉数据模型:

  • Observable:广播事件
  • Updatable:监听事件,从 Repository 拉取数据
1
2
3
4
5
6
7
8
9
// 概念示例(Agera 已归档,仅作了解)
val repository = Repositories.repositoryWithInitialValue(initialData)
.observe()
.onUpdatesPerLoop()
.getFrom { fetchFromNetwork() }
.compile()

repository.addUpdatable(updatable)
// 事件触发时,Updatable 从 Repository 拉取最新数据

注意:Agera 已于 2023 年 3 月归档,新项目建议使用 Kotlin Flow / StateFlow。

6.3 Jetpack Compose 状态管理

6.3.1 remember + mutableStateOf

1
2
3
4
5
6
7
@Composable
fun Counter() {
var count by remember { mutableStateOf(0) }
Button(onClick = { count++ }) {
Text("Count: $count")
}
}
  • remember:在重组间保持值,避免每次重组重新创建
  • mutableStateOf:创建可观察状态,读该状态的 Composable 会在值变化时重组

6.3.2 状态提升(State Hoisting)

1
2
3
4
5
6
7
8
9
10
11
12
@Composable
fun Parent() {
var count by remember { mutableStateOf(0) }
Child(count = count, onCountChange = { count = it })
}

@Composable
fun Child(count: Int, onCountChange: (Int) -> Unit) {
Button(onClick = { onCountChange(count + 1) }) {
Text("$count")
}
}

6.3.3 ViewModel + StateFlow

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class MyViewModel : ViewModel() {
private val _state = MutableStateFlow(MyState())
val state: StateFlow<MyState> = _state.asStateFlow()

fun update() {
_state.update { it.copy(...) }
}
}

@Composable
fun Screen(viewModel: MyViewModel = viewModel()) {
val state by viewModel.state.collectAsStateWithLifecycle()
// 使用 state
}

6.3.4 配置变更保留:rememberSaveable

1
2
var count by rememberSaveable { mutableStateOf(0) }
// 屏幕旋转等配置变更后,count 会保留

七、鸿蒙:ArkTS

7.1 装饰器驱动的状态

ArkTS 通过装饰器声明「可观察」状态,状态变化自动触发 UI 更新。

7.1.1 @State:组件内部状态

1
2
3
4
5
6
7
8
9
10
11
12
@Entry
@Component
struct Counter {
@State count: number = 0
build() {
Column() {
Text(`Count: ${this.count}`)
Button('+1')
.onClick(() => { this.count++ })
}
}
}

7.1.2 @Prop:父 → 子单向

1
2
3
4
5
6
7
8
9
10
@Component
struct Child {
@Prop value: number // 父组件传入,子组件只读
build() {
Text(`${this.value}`)
}
}

// 父组件
Child({ value: this.count })

7.1.3 @Link:父子双向

1
2
3
4
5
6
7
8
9
10
@Component
struct Child {
@Link value: number // 子组件修改会同步回父组件
build() {
Button('+1').onClick(() => { this.value++ })
}
}

// 父组件
Child({ value: $count }) // $ 语法传递引用

7.1.4 @Provide / @Consume:跨层级

1
2
3
4
5
// 祖先
@Provide('theme') theme: string = 'light'

// 任意后代
@Consume('theme') theme: string

7.1.5 @Observed + @ObjectLink:嵌套对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Observed
class User {
name: string
constructor(name: string) { this.name = name }
}

@Component
struct UserView {
@ObjectLink user: User
build() {
Text(this.user.name)
.onClick(() => { this.user.name = 'New' }) // 触发更新
}
}

7.2 状态管理 V2(@ObservedV2 + @Trace)

V2 支持深层属性观察,解决嵌套对象内部属性不可观察的问题。


八、跨平台对比与选型

8.1 概念映射表

概念 React Flutter SwiftUI Jetpack Compose ArkTS
组件内状态 useState State @State remember + mutableStateOf @State
父子单向 props 构造函数参数 普通参数 参数 @Prop
父子双向 回调 + props 回调 @Binding 回调 + 参数 @Link
跨层级 Context Provider/InheritedWidget EnvironmentObject CompositionLocal @Provide/@Consume
引用类型 useRef/Context ChangeNotifier @ObservableObject ViewModel @Observed+@ObjectLink

8.2 选型建议

场景 推荐方案
简单 UI 状态 各平台内置(useState / @State / remember)
跨组件共享 Context / Provider / ViewModel / @Provide
复杂异步流 RxSwift / RxJava / Kotlin Flow
服务端数据 React Query / SWR / ViewModel + Repository
Next.js 全栈 Server Components 拉数据 + Client 管理交互态
新 Android 项目 Jetpack Compose + ViewModel + StateFlow
新 iOS 项目 SwiftUI + @Observable
鸿蒙应用 ArkUI 装饰器体系

九、源码原理浅析

9.1 React:Fiber 与 Hooks 链表

React 在 Fiber 节点上维护 memoizedState 链表,每个 Hook 对应链表中的一个节点:

1
2
3
4
5
Fiber.memoizedState → useState → useEffect → useContext → ...

├─ baseState
├─ baseQueue
└─ next (下一个 Hook)

setState 会将更新放入队列,调度器在合适时机执行重渲染,按顺序应用更新,保证 Hooks 调用顺序稳定。

9.2 Jetpack Compose:快照与重组

Compose 使用 Snapshot 系统追踪状态读取:

  1. mutableStateOf 创建 SnapshotMutableState
  2. 读取 state.value 时,当前 Composable 的「重组作用域」会记录对该 state 的依赖
  3. 写入 state.value = x 时,Compose 标记依赖该 state 的作用域需要重组
  4. 重组时重新执行对应 Composable,得到新 UI
1
读取 state → 记录依赖 → 写入 state → 标记无效 → 调度重组 → 重新执行 Composable

9.3 SwiftUI:@State 与依赖追踪

SwiftUI 在编译期和运行期结合,追踪 body 中对 @State 等属性的访问。当 @State 变化时,视图的 body 会重新求值,生成新的 View 描述,再与旧描述 diff 后更新真实视图。

9.4 ArkTS:装饰器与更新调度

@State 等装饰器在编译期生成观察逻辑,运行时状态变化会标记组件为脏,下一帧统一执行 build 更新 UI,类似 Flutter 的 setState + 帧调度。


十、实战案例

10.1 登录表单校验(多字段组合)

需求:用户名 ≥3 字符、密码 ≥6 字符时,登录按钮才可点击。

React

1
2
3
4
const [user, setUser] = useState('');
const [pwd, setPwd] = useState('');
const canLogin = user.length >= 3 && pwd.length >= 6;
return <Button disabled={!canLogin}>登录</Button>;

SwiftUI

1
2
3
4
@State private var user = ""
@State private var pwd = ""
var canLogin: Bool { user.count >= 3 && pwd.count >= 6 }
Button("登录") { }.disabled(!canLogin)

Jetpack Compose

1
2
3
4
var user by remember { mutableStateOf("") }
var pwd by remember { mutableStateOf("") }
val canLogin = user.length >= 3 && pwd.length >= 6
Button(onClick = {}, enabled = canLogin) { Text("登录") }

ArkTS

1
2
3
4
5
6
@State user: string = ''
@State pwd: string = ''
private get canLogin(): boolean {
return this.user.length >= 3 && this.pwd.length >= 6
}
Button('登录').enabled(this.canLogin)

10.2 搜索防抖 + 取消旧请求

React

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const [keyword, setKeyword] = useState('');
const [results, setResults] = useState([]);

useEffect(() => {
if (keyword.length < 2) return;
const timer = setTimeout(() => {
let cancelled = false;
search(keyword).then(data => {
if (!cancelled) setResults(data);
});
return () => { cancelled = true; };
}, 300);
return () => clearTimeout(timer);
}, [keyword]);

RxSwift

1
2
3
4
5
6
7
searchTextField.rx.text.orEmpty
.filter { $0.count >= 2 }
.debounce(.milliseconds(300), scheduler: MainScheduler.instance)
.flatMapLatest { api.search($0) }
.observe(on: MainScheduler.instance)
.bind(to: resultsRelay)
.disposed(by: disposeBag)

Jetpack Compose + ViewModel

1
2
3
4
5
6
val query = MutableStateFlow("")
val results = query
.debounce(300)
.filter { it.length >= 2 }
.flatMapLatest { repository.search(it) }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptyList())

10.3 购物车总价实时计算

Flutter (Provider)

1
2
3
4
5
class CartModel extends ChangeNotifier {
final List<CartItem> _items = [];
double get total => _items.fold(0, (sum, item) => sum + item.price * item.qty);
void add(CartItem item) { _items.add(item); notifyListeners(); }
}

React

1
2
3
4
5
const [items, setItems] = useState([]);
const total = useMemo(
() => items.reduce((s, i) => s + i.price * i.qty, 0),
[items]
);

10.4 Next.js 服务端数据 + 客户端状态

1
2
3
4
5
6
7
8
9
10
// app/product/[id]/page.tsx
export default async function Page({ params }: { params: { id: string } }) {
const product = await fetchProduct(params.id); // 服务端拉取
return (
<div>
<ProductInfo product={product} />
<AddToCartButton productId={product.id} /> {/* 内部用 useState 管理数量 */}
</div>
);
}

十一、总结与最佳实践

11.1 核心要点

维度 共性
本质 状态驱动 UI,变化触发更新
模式 单向数据流、观察者、单一数据源
局部 vs 全局 按范围选择合适的共享机制
生命周期 状态与组件/页面生命周期绑定,避免泄漏

11.2 最佳实践

  1. 最小化状态:能推导的不要存储,用 useMemo / computed / getter
  2. 状态提升:当多组件需要共享时,提升到共同祖先
  3. 不可变更新:避免直接修改,使用 setState/copy/扩展运算符
  4. 副作用清理useEffect 清理、Disposable.disposeviewModelScope
  5. 服务端状态分离:与 UI 状态区分,用专门库(React Query 等)管理
  6. 类型安全:TypeScript、Swift、Kotlin 充分利用类型约束状态结构

11.3 各平台快速对照

平台 局部状态 共享状态 异步/流式
React useState Context / Redux useEffect / React Query
Next.js useState (Client) Context (Client) Server Components + fetch
Flutter State / ValueNotifier Provider / Riverpod Stream / Future
SwiftUI @State @ObservableObject / Environment async/await
RxSwift Observable / Subject 同上 + Subject Observable 链
Compose remember + mutableStateOf ViewModel + StateFlow Flow / LaunchedEffect
ArkTS @State @Provide / @Consume Promise / async

参考资源

跨平台响应式状态管理实现原理深度分析

目录


一、响应式编程基础

1.1 核心概念

响应式编程是一种编程范式,其核心思想是:

  • 数据驱动UI:UI是数据的函数 UI = f(state)
  • 自动更新:当数据变化时,UI自动更新
  • 声明式:只关注”是什么”,不关注”怎么做”

状态管理是响应式编程的核心,解决的问题包括:

  • 状态的存储和访问
  • 状态变化的检测和通知
  • 副作用的处理
  • 状态的持久化

1.2 响应式系统的基本构成

一个完整的响应式系统通常包含以下组件:

组件 作用 实现方式
状态容器 存储应用状态 变量、对象、状态树
订阅机制 监听状态变化 观察者模式、发布-订阅模式
变更检测 检测状态变化 脏检查、依赖追踪、响应式代理
渲染引擎 更新UI 虚拟DOM、真实DOM操作、Widget重建
调度器 优化更新时机 批处理、微任务队列、动画帧

二、iOS响应式状态管理

2.1 传统KVO机制

核心原理

  • 键值观察(Key-Value Observing)是iOS的原生响应式机制
  • 基于运行时的动态方法替换
  • 使用isa-swizzling技术实现属性观察

实现机制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 1. 注册观察者
[object addObserver:self
forKeyPath:@"propertyName"
options:NSKeyValueObservingOptionNew
context:NULL];

// 2. 实现观察回调
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context {
if ([keyPath isEqualToString:@"propertyName"]) {
id newValue = change[NSKeyValueChangeNewKey];
// 更新UI
}
}

// 3. 移除观察者
- (void)dealloc {
[object removeObserver:self forKeyPath:@"propertyName"];
}

技术深度

  • KVO通过动态创建子类实现,当对象被观察时,系统会:
    1. 创建一个继承自原类的子类
    2. 重写被观察属性的setter方法
    3. 替换对象的isa指针指向新子类
    4. 在setter中通知观察者

2.2 Combine框架

核心原理

  • Apple在iOS 13+推出的响应式编程框架
  • 基于Publisher-Subscriber模式
  • 支持函数式的响应式操作

实现机制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 1. 创建Publisher
let subject = PassthroughSubject<String, Never>()

// 2. 订阅
let cancellable = subject
.map { $0.uppercased() }
.filter { $0.count > 3 }
.sink {
print("Received: \($0)")
}

// 3. 发送值
subject.send("Hello")
subject.send("World")

// 4. 取消订阅
cancellable.cancel()

技术深度

  • Combine使用协议泛型实现类型安全
  • Publisher:数据源,负责发送值
  • Subscriber:订阅者,接收并处理值
  • Operator:操作符,对数据流进行转换
  • Cancellable:管理订阅生命周期

2.3 SwiftUI状态管理

核心原理

  • 声明式UI框架,与响应式状态管理深度集成
  • 使用属性包装器简化状态管理
  • 基于依赖追踪的更新机制

实现机制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// 1. @State - 本地状态
struct ContentView: View {
@State private var count = 0

var body: some View {
VStack {
Text("Count: \(count)")
Button("Increment") {
count += 1
}
}
}
}

// 2. @ObservableObject - 可观察对象
class UserViewModel: ObservableObject {
@Published var name: String

init(name: String) {
self.name = name
}
}

struct UserView: View {
@ObservedObject var viewModel: UserViewModel

var body: some View {
Text("Name: \(viewModel.name)")
}
}

技术深度

  • @State:使用值类型的引用包装,支持本地状态
  • @Published:使用属性包装器实现自动通知
  • @ObservedObject:使用弱引用避免循环引用
  • @EnvironmentObject:通过环境传递共享状态

三、Flutter响应式状态管理

3.1 基础状态管理(setState)

核心原理

  • 基于StatefulWidgetsetState的基础状态管理
  • 脏检查机制触发重建
  • Element树的差异化更新

实现机制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class CounterWidget extends StatefulWidget {
@override
_CounterWidgetState createState() => _CounterWidgetState();
}

class _CounterWidgetState extends State<CounterWidget> {
int _count = 0;

void _increment() {
setState(() {
_count++;
});
}

@override
Widget build(BuildContext context) {
return Column(
children: [
Text('Count: $_count'),
ElevatedButton(
onPressed: _increment,
child: Text('Increment'),
),
],
);
}
}

技术深度

  • setState:标记Element为dirty,触发下一帧重建
  • Widget树:不可变的配置树
  • Element树:管理生命周期和状态
  • RenderObject树:负责布局和渲染

3.2 InheritedWidget机制

核心原理

  • 基于继承的状态传递机制
  • 利用Element树的层级关系
  • 实现跨组件的状态共享

实现机制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
class AppState extends InheritedWidget {
final int count;
final VoidCallback increment;

const AppState({
Key? key,
required this.count,
required this.increment,
required Widget child,
}) : super(key: key, child: child);

static AppState of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<AppState>()!;
}

@override
bool updateShouldNotify(AppState oldWidget) {
return oldWidget.count != count;
}
}

// 使用
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
int _count = 0;

void _increment() {
setState(() => _count++);
}

@override
Widget build(BuildContext context) {
return AppState(
count: _count,
increment: _increment,
child: MaterialApp(
home: HomePage(),
),
);
}
}

class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final appState = AppState.of(context);
return Column(
children: [
Text('Count: ${appState.count}'),
ElevatedButton(
onPressed: appState.increment,
child: Text('Increment'),
),
],
);
}
}

技术深度

  • dependOnInheritedWidgetOfExactType:建立依赖关系
  • updateShouldNotify:决定是否通知子组件
  • Element依赖追踪:当InheritedWidget变化时,自动重建依赖的子组件

3.3 第三方状态管理库

Provider

核心原理

  • 基于InheritedWidget的轻量级状态管理
  • 使用ChangeNotifier实现状态通知
  • 支持依赖注入状态监听

实现机制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// 1. 定义模型
class CounterModel extends ChangeNotifier {
int _count = 0;
int get count => _count;

void increment() {
_count++;
notifyListeners();
}
}

// 2. 提供状态
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => CounterModel(),
child: MyApp(),
),
);
}

// 3. 消费状态
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Consumer<CounterModel>(
builder: (context, counter, child) {
return Column(
children: [
Text('Count: ${counter.count}'),
ElevatedButton(
onPressed: counter.increment,
child: Text('Increment'),
),
],
);
},
);
}
}

技术深度

  • ChangeNotifier:实现观察者模式
  • Consumer:订阅状态变化,只重建必要的Widget
  • Selector:更精确的依赖选择,避免不必要的重建

Riverpod

核心原理

  • 解决Provider的依赖注入测试问题
  • 基于ProviderContainer的状态管理
  • 支持编译时安全懒加载

实现机制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 1. 定义Provider
final counterProvider = StateProvider<int>((ref) => 0);

// 2. 使用Provider
class HomePage extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final count = ref.watch(counterProvider);

return Column(
children: [
Text('Count: $count'),
ElevatedButton(
onPressed: () => ref.read(counterProvider.notifier).state++,
child: Text('Increment'),
),
],
);
}
}

// 3. 组合Provider
final userProvider = Provider<User>((ref) {
final userId = ref.watch(userIdProvider);
return User(id: userId);
});

技术深度

  • ProviderScope:状态容器,支持测试和隔离
  • AutoDispose:自动清理不再使用的状态
  • Family:参数化Provider,支持动态创建
  • FutureProvider:处理异步状态
  • StreamProvider:处理流式状态

四、React响应式状态管理

4.1 基础状态管理(setState)

核心原理

  • 基于ComponentsetState的状态管理
  • 虚拟DOM的差异化更新
  • 批处理优化性能

实现机制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
}

increment() {
this.setState(prevState => ({
count: prevState.count + 1
}));
}

render() {
return (
<div>
<p>Count: {this.state.count}</p>
<button onClick={() => this.increment()}>Increment</button>
</div>
);
}
}

技术深度

  • setState:异步更新,支持函数式更新
  • shouldComponentUpdate:手动优化渲染
  • PureComponent:浅比较优化
  • forceUpdate:强制更新

4.2 Hooks状态管理

核心原理

  • React 16.8+引入的函数组件状态管理
  • 基于闭包链表的Hook实现
  • 支持自定义Hook复用逻辑

实现机制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import React, { useState, useEffect } from 'react';

function Counter() {
const [count, setCount] = useState(0);

useEffect(() => {
document.title = `Count: ${count}`;
}, [count]);

return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}

技术深度

  • useState:基于Dispatcher的状态管理
  • useEffect:处理副作用,依赖数组控制执行时机
  • useContext:跨组件状态共享
  • useReducer:复杂状态逻辑管理
  • useMemo/useCallback:性能优化

4.3 Redux状态管理

核心原理

  • 基于Flux架构的状态管理
  • 单一数据源不可变状态
  • Reducer纯函数处理状态更新

实现机制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
// 1. 定义Action
const INCREMENT = 'INCREMENT';
const DECREMENT = 'DECREMENT';

// 2. 定义Reducer
function counterReducer(state = { count: 0 }, action) {
switch (action.type) {
case INCREMENT:
return { count: state.count + 1 };
case DECREMENT:
return { count: state.count - 1 };
default:
return state;
}
}

// 3. 创建Store
const store = createStore(counterReducer);

// 4. 订阅状态
store.subscribe(() => {
console.log('Current state:', store.getState());
});

// 5. 分发Action
store.dispatch({ type: INCREMENT });

// 6. 在React中使用
import { connect } from 'react-redux';

function Counter({ count, increment, decrement }) {
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
</div>
);
}

const mapStateToProps = state => ({
count: state.count
});

const mapDispatchToProps = dispatch => ({
increment: () => dispatch({ type: INCREMENT }),
decrement: () => dispatch({ type: DECREMENT })
});

export default connect(mapStateToProps, mapDispatchToProps)(Counter);

技术深度

  • Store:单一数据源,持有应用状态
  • Action:描述状态变化的对象
  • Reducer:纯函数,根据Action计算新状态
  • Middleware:处理异步Action和副作用
  • CombineReducers:拆分状态逻辑

五、React Native响应式状态管理

5.1 原生状态管理

核心原理

  • 与React相同的状态管理机制
  • 针对移动平台的优化
  • 支持原生模块的状态同步

实现机制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import React, { useState } from 'react';
import { View, Text, TouchableOpacity } from 'react-native';

function Counter() {
const [count, setCount] = useState(0);

return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text style={{ fontSize: 24 }}>Count: {count}</Text>
<TouchableOpacity
style={{ marginTop: 20, padding: 10, backgroundColor: '#007AFF' }}
onPress={() => setCount(count + 1)}
>
<Text style={{ color: 'white' }}>Increment</Text>
</TouchableOpacity>
</View>
);
}

技术深度

  • Bridge:JavaScript与原生通信
  • Shadow Tree:虚拟DOM在RN中的实现
  • Batched Updates:批量更新优化
  • Native Modules:原生功能集成

5.2 第三方状态管理库

Redux

核心原理

  • 与React Redux相同的架构
  • 针对移动场景的优化
  • 支持持久化中间件

实现机制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 与Web React Redux相同
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers';

const store = createStore(
rootReducer,
applyMiddleware(thunk)
);

// 在App中使用
import { Provider } from 'react-redux';

export default function App() {
return (
<Provider store={store}>
<Counter />
</Provider>
);
}

MobX

核心原理

  • 基于观察者模式的状态管理
  • 响应式代理自动追踪依赖
  • 装饰器简化状态定义

实现机制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import { observable, action } from 'mobx';
import { observer } from 'mobx-react';

// 定义Store
class CounterStore {
@observable count = 0;

@action increment() {
this.count++;
}

@action decrement() {
this.count--;
}
}

const counterStore = new CounterStore();

// 使用Store
@observer
class Counter extends React.Component {
render() {
return (
<View>
<Text>Count: {counterStore.count}</Text>
<TouchableOpacity onPress={() => counterStore.increment()}>
<Text>Increment</Text>
</TouchableOpacity>
</View>
);
}
}

技术深度

  • observable:创建响应式状态
  • action:修改状态的方法
  • computed:派生状态
  • reaction:副作用处理

Context API

核心原理

  • React 16.3+的Context API
  • 简化跨组件状态共享
  • 替代Redux的轻量级方案

实现机制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import React, { createContext, useContext, useState } from 'react';

// 创建Context
const CounterContext = createContext();

// 提供Context
function CounterProvider({ children }) {
const [count, setCount] = useState(0);

const value = {
count,
increment: () => setCount(count + 1),
decrement: () => setCount(count - 1)
};

return (
<CounterContext.Provider value={value}>
{children}
</CounterContext.Provider>
);
}

// 使用Context
function Counter() {
const { count, increment, decrement } = useContext(CounterContext);

return (
<View>
<Text>Count: {count}</Text>
<TouchableOpacity onPress={increment}>
<Text>Increment</Text>
</TouchableOpacity>
<TouchableOpacity onPress={decrement}>
<Text>Decrement</Text>
</TouchableOpacity>
</View>
);
}

// 在App中使用
function App() {
return (
<CounterProvider>
<Counter />
</CounterProvider>
);
}

六、鸿蒙响应式状态管理

6.1 ArkUI状态管理

核心原理

  • 鸿蒙ArkUI框架的响应式状态管理
  • 基于数据驱动的UI更新
  • 支持声明式命令式编程

实现机制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// 1. 基本状态管理
@Entry
@Component
struct Counter {
@State count: number = 0;

build() {
Column() {
Text(`Count: ${this.count}`)
.fontSize(24)
Button('Increment')
.onClick(() => {
this.count++;
})
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Center)
}
}

// 2. 全局状态管理
@StorageLink('count')
let globalCount: number = 0;

@Entry
@Component
struct GlobalCounter {
build() {
Column() {
Text(`Global Count: ${globalCount}`)
.fontSize(24)
Button('Increment')
.onClick(() => {
globalCount++;
})
}
}
}

技术深度

  • @State:组件级状态,局部更新
  • @Prop:父组件传递的状态,单向数据流
  • @Link:双向绑定状态
  • @StorageLink:全局存储状态
  • @Provide/@Consume:跨组件状态共享

6.2 状态管理最佳实践

核心原理

  • 结合MVVM架构
  • 使用状态管理器统一管理状态
  • 支持异步操作副作用处理

实现机制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
// 定义状态管理器
class CounterStore {
private _count: number = 0;
private _observers: Set<() => void> = new Set();

get count(): number {
return this._count;
}

increment(): void {
this._count++;
this.notifyObservers();
}

decrement(): void {
this._count--;
this.notifyObservers();
}

subscribe(observer: () => void): void {
this._observers.add(observer);
}

unsubscribe(observer: () => void): void {
this._observers.delete(observer);
}

private notifyObservers(): void {
this._observers.forEach(observer => observer());
}
}

// 使用状态管理器
const counterStore = new CounterStore();

@Entry
@Component
struct Counter {
@State count: number = counterStore.count;

aboutToAppear(): void {
counterStore.subscribe(() => {
this.count = counterStore.count;
});
}

build() {
Column() {
Text(`Count: ${this.count}`)
.fontSize(24)
Button('Increment')
.onClick(() => {
counterStore.increment();
})
}
}
}

技术深度

  • 单向数据流:状态变化 → UI更新
  • 可观测性:状态变化自动通知
  • 模块化:状态逻辑与UI分离
  • 可测试性:纯函数状态更新

七、性能优化与对比

7.1 性能优化策略

平台 优化策略 技术实现 性能提升
iOS 批处理更新 Combine Scheduler 30-40%
避免KVO滥用 使用Combine 20-30%
缓存计算值 @Published + 缓存 15-25%
Flutter 减少重建 const Widget + Key 40-50%
状态隔离 RepaintBoundary 25-35%
懒加载 FutureBuilder + 缓存 30-40%
React 避免重渲染 shouldComponentUpdate 30-40%
记忆化 useMemo + useCallback 20-30%
批量更新 React 18 Automatic Batching 15-25%
React Native 桥接优化 Hermes引擎 40-50%
减少渲染 React.memo 25-35%
原生模块 避免JSBridge 30-40%
鸿蒙 组件复用 @Builder 30-40%
状态管理 @StorageLink 20-30%
渲染优化 声明式UI 25-35%

7.2 平台对比

特性 iOS Flutter React React Native 鸿蒙
响应式模型 Combine + SwiftUI InheritedWidget + Provider setState + Hooks setState + Hooks @State + @StorageLink
状态管理库 Combine, RxSwift Provider, Riverpod, Bloc Redux, MobX, Context API Redux, MobX, Context API 内置状态管理 + 自定义Store
性能
开发效率
学习曲线
跨平台

7.3 性能瓶颈分析

iOS

  • KVO的运行时开销
  • Combine的内存管理
  • SwiftUI的重建机制

Flutter

  • Widget重建开销
  • 状态管理的性能开销
  • 渲染管线的优化

React

  • 虚拟DOM的diff开销
  • 重渲染的性能损耗
  • 状态管理的复杂性

React Native

  • JSBridge的通信开销
  • 原生模块的调用延迟
  • 渲染性能的限制

鸿蒙

  • 状态管理的同步问题
  • 组件生命周期的管理
  • 性能优化的复杂度

八、最佳实践与架构选型

8.1 架构选型指南

应用规模 推荐架构 适用平台 优势
小型应用 基础状态管理 所有平台 简单直接,开发效率高
中型应用 Provider/Riverpod Flutter 轻量级,易于集成
Context API + useReducer React/React Native 内置方案,无需依赖
Combine + ObservableObject iOS 原生支持,性能好
@State + @StorageLink 鸿蒙 内置方案,开发简单
大型应用 Redux + 中间件 React/React Native 可预测性强,易于调试
Bloc + Stream Flutter 清晰的状态流转
RxSwift + MVVM iOS 响应式能力强
自定义Store + 状态管理 鸿蒙 可扩展性好

8.2 最佳实践

1. 状态管理分层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
应用架构
┌─────────────────────────┐
│ UI Layer │
│ (View/Widget/Component) │
├─────────────────────────┤
│ State Management Layer │
│ (Store/Provider/Context) │
├─────────────────────────┤
│ Business Logic Layer │
│ (UseCase/Service) │
├─────────────────────────┤
│ Data Layer │
│ (Repository/API) │
└─────────────────────────┘

2. 状态管理原则

  • 单一数据源:避免状态分散
  • 不可变状态:确保状态变化可预测
  • 单向数据流:状态 → UI → 事件 → 状态
  • 分离关注点:业务逻辑与UI分离
  • 可测试性:状态管理逻辑可独立测试

3. 性能优化最佳实践

  • iOS:使用Combine的调度器,避免KVO滥用
  • Flutter:使用const Widget,合理使用Key,优化重建
  • React:使用memo,合理设置依赖数组,避免不必要的渲染
  • React Native:使用Hermes引擎,优化桥接通信
  • 鸿蒙:合理使用状态注解,优化组件渲染

4. 团队协作建议

  • 统一状态管理方案:团队内使用一致的状态管理库
  • 文档化状态结构:清晰记录状态的结构和流转
  • 代码规范:建立状态管理的代码规范
  • 测试策略:为状态管理逻辑编写单元测试
  • 性能监控:建立性能监控机制

总结

响应式状态管理是现代前端和移动开发的核心技术之一,不同平台有其独特的实现原理和最佳实践:

  1. iOS:从KVO到Combine再到SwiftUI,逐步演进为更现代的响应式方案
  2. Flutter:基于Widget树和InheritedWidget,构建了独特的响应式体系
  3. React:从setState到Hooks,简化了状态管理的复杂性
  4. React Native:继承了React的状态管理机制,针对移动平台进行了优化
  5. 鸿蒙:基于ArkUI框架,提供了声明式的状态管理方案

选择合适的状态管理方案需要考虑:

  • 应用规模:小型应用使用简单方案,大型应用使用复杂方案
  • 性能要求:对性能敏感的应用需要更精细的状态管理
  • 团队经验:选择团队熟悉的技术栈
  • 维护成本:考虑长期维护的复杂性

通过深入理解各平台的响应式状态管理原理,开发者可以构建更高效、更可维护的应用,提升用户体验和开发效率。

Flutter 主流状态管理库:选型、原理与源码导读

本文从工程选型出发,对比 Flutter 生态中常用的状态管理方案,并给出实现思路与源码阅读入口,便于结合官方仓库深入学习。

目录


一、如何理解「状态管理」在 Flutter 中的位置

Flutter 的 UI 由 **Widget 配置树** 描述;真正随数据变化而刷新的,依赖 **Element / RenderObject** 的更新机制。状态管理解决的是:把业务数据放在哪、如何通知依赖它的 Widget 重建、如何组织可测试的业务逻辑。

选型时通常看:学习曲线、样板代码量、与测试/依赖注入的契合度、团队习惯、是否强约束数据流


二、设计思想与经典模式

状态管理库里的常见做法,多半能在经典设计思想里找到落点:谁在存状态、谁订阅变化、谁负责把变化交给 UI。下面是与本文各方案最相关的几种;它们在实际工程里往往组合出现,而不是非此即彼。

2.1 观察者模式(Observer)

含义:被观察对象(Subject)在状态变化时通知一组观察者(Observer),由观察者决定如何更新。
在 Flutter 里Listenable / ChangeNotifier 是典型的「可订阅 + 广播通知」;ValueNotifier 是带当前值的特化。notifyListeners() 对应 Subject 发通知ValueListenableBuilder / AnimatedBuilder 等对应 Observer 侧的重建入口
与各方案:Provider + ChangeNotifier、以及 UI 侧订阅 Stream<State>BlocBuilder,都体现观察者思想;Bloc 一侧更强调 随时间展开的异步事件流

2.2 发布—订阅(Pub/Sub)与响应式流

与观察者同属「一对多通知」,但常强调 发送方与订阅方解耦、中间可有 异步缓冲Stream / StreamController、Bloc 的 Stream<State>、Riverpod 的 ref.listen(副作用订阅)都可归入这一族:状态或事件沿时间轴推送给订阅者,便于表达多步异步与管线化逻辑(Bloc 尤为典型)。

2.3 依赖注入(DI)与服务定位器(Service Locator)

含义:由外部组装依赖,调用方依赖抽象而非在内部直接 new 具体实现,便于替换与测试。
在 Flutter 里InheritedWidget、Provider、Riverpod 的 ProviderScope + ref.read,以及 GetX 的 Get.put / Get.find,都在做「把实现挂到某处,子树或全局按类型 / key 取用」。差异主要在生命周期(是否与 Element 树绑定、是否全局单例)以及 Riverpod 带来的 编译期与依赖图层面的安全

2.4 命令模式(Command)与显式状态(Bloc)

Bloc 中的 **Event 可视为命令对象**:UI 不直接改领域状态,而是派发事件,由 Bloc 统一解释并 emitState。再配合不可变、可穷举的 State 类型描述界面阶段,相当于把业务规则收拢到「命令处理 + 状态迁移」,利于单测与行为审计。Cubit 则是用 方法调用 代替显式 Event 类型,思想仍相近。

2.5 外观(Facade)、组合根与依赖倒置

InheritedWidget 手写成本高,Provider 等库在其上提供更易用的 Facade 式 APIRiverpodProviderContainer 把依赖图从整棵 BuildContext 树里抽出一层,更接近在应用入口做 组合根(Composition Root) 集中装配。分层架构里常配合 依赖倒置:领域层定义接口,具体实现由外层注入——与上述 DI 能力天然契合。

2.6 各方案与上述思想的对应(速查)

方案 / API 主要涉及的设计思想
setState 命令式更新;框架 脏标记 驱动单棵子树重建
ValueNotifier + ValueListenableBuilder 观察者Listenable
Provider + ChangeNotifier DI / 服务定位InheritedWidget 查找)+ 观察者notifyListeners
Riverpod 组合根 + 依赖图 + 依赖追踪下的观察者式失效ref.watch
Bloc / Cubit 命令(Event)或方法入口 + 显式 State + Pub/Sub 式 Stream
GetX 服务定位 / 全局注入 + 响应式更新(具体可测试性高度依赖团队约定)

理清这些对应关系,再读各库的 watchlistenreademit 等 API,会少很多「名不同、实相近」的困惑。


三、内置与轻量方案

3.1 setState

  • 优点:零依赖,心智负担小,适合局部、短命状态。
  • 缺点:逻辑与 UI 耦在 State 里,规模一大难以拆分与单测。
  • 适用:页面内表单开关、动画控制器等。
  • 原理setState 标记 Element dirty,在下一帧 build 中重建子树。

3.2 ValueNotifier + ValueListenableBuilder

  • 优点:对象级可监听,比 setState 更易抽到类字段中。
  • 缺点:跨页面传递需手动层层传参或自己封装 InheritedWidget
  • 适用:单页面内一块 UI 依赖单个标量/小对象。
  • 原理Listenable 通知监听者;ValueListenableBuilderbuild 中注册监听并重建。

四、Provider

定位:在 InheritedWidget 之上封装「依赖查找 + 更新传播」,常与 **ChangeNotifier** 搭配。

维度 说明
优点 官方文档与示例多;API 面相对小;MultiProvider 组合清晰;与 ChangeNotifier 成熟。
缺点 大型应用中 ChangeNotifier 类易膨胀;依赖树与 BuildContext 绑定,错误 context 易导致找不到 Provider。
适用 中小型 App、从入门到中等复杂度的业务模块。
原理要点 Provider/Consumer 等通过 InheritedWidget 向下提供值;ChangeNotifier 通知时触发 notifyListeners(),依赖的 Consumer/context.watch 重建。

五、Riverpod

定位:Provider 作者推出的「下一代」,编译期安全 + 全局注册表,弱化对 BuildContext 的依赖(ref 为主)。

维度 说明
优点 类型与依赖关系更清晰;Provider 可组合、覆盖测试;异步/家族参数(family)表达力强。
缺点 概念多(NotifierAsyncNotifier、代码生成可选);团队需统一规范。
适用 中大型项目、需要可测试依赖图与清晰模块边界的团队。
原理要点 **ProviderContainer** 持有所有 Provider 的状态;ref.watch/read/listen 建立依赖;更新时按依赖图失效下游。代码生成路径下由 **riverpod_generator** 生成 `.g.dart*。

六、Bloc / Cubit(flutter_bloc)

定位事件驱动 + 显式状态转移CubitBloc 的简化(方法调用代替 Event 类型)。

维度 说明
优点 数据流单向、状态机思维清晰;时间旅行调试(BlocObserver);与分层架构、单测契合好。
缺点 样板代码多(Event/State 类);小功能也显重。
适用 复杂业务流、多分支异步、需严格审计状态变化的场景(支付、登录流程、长表单步骤)。
原理要点 Bloc 接收 Event,在 mapEventToState(或新版 handler)中 **emitStateBlocBuilder/BlocListener 订阅 Stream<State>;底层基于 **Stream + Sink 与协调调度。

七、GetX(简述)

维度 说明
优点 路由、依赖注入、状态一套 API,上手快;写法省代码。
缺点 与 Flutter 官方推荐的数据流模式差异大;社区对「隐式全局」与可测试性争议多;大版本与迁移成本需自行评估。
适用 快速原型、小团队强约定场景;企业级长期维护前建议充分评估。

八、横向对比与适用场景

方案 学习成本 样板代码 可测试性 与官方范式契合
setState / ValueNotifier 中(看拆分)
Provider + ChangeNotifier 低~中 中高
Riverpod 中~高 中(+ 生成器)
Bloc/Cubit
GetX 低~中 视用法而定

场景建议(概括)

  • 页面内小状态setState / ValueNotifier
  • 多页面共享、中等规模ProviderRiverpod(更看团队是否愿意引入 Riverpod 心智模型)。
  • 强流程、多事件、要画清状态机Bloc/Cubit
  • 极快交付且团队接受其风格:可考察 GetX,并做好规范与评审。

九、实现原理归纳

  1. 依赖向下、通知向上InheritedWidget / Provider / Riverpod 本质是「子树查找 + 依赖追踪」。
  2. Listenable / StreamChangeNotifierBloc 分别代表 拉模型监听推模型流 两类更新机制。
  3. 刷新粒度:从「整页 setState」到「Selector/select 只重建一部分」,是性能与 API 设计的共同主题。
  4. Riverpod:把「谁依赖谁」放在 容器里统一管理,而不是仅靠 BuildContext 树,这是和经典 Provider 的重要区别。
  5. 与经典模式的对照:观察者、Listenable / Stream 两类通知、依赖注入与组合根等,在 第二节 已从「设计思想」角度归纳,可与上四条穿插阅读。

十、源码导读:从哪几个文件读起

下面列出 Pub 上包名 与建议阅读顺序(以 GitHub 托管为准,分支以主分支为例)。阅读时结合你项目里 pubspec.yaml 锁定的版本更佳。

10.1 provider

  • 仓库:flutter/packages 中的 **provider** 包(或社区维护的 provider 独立仓库,以 pub.dev 主页为准)。
  • 入口lib/src/provider.dartinherited_provider.dart — 看 InheritedWidget 如何包装 value / delegate
  • ChangeNotifier 集成change_notifier_provider.dartListenableElement 更新如何衔接。

10.2 flutter_riverpod / riverpod

  • 仓库:**rrousselGit/riverpod**。
  • 核心lib/src/framework/container.dartProviderContainer)、provider/base.dart 一带 — 理解 Provider 状态存哪、如何失效
  • 注解与生成:若用代码生成,配合阅读 **riverpod_generator** 生成的 *.g.dartriverpod_annotation

10.3 bloc / flutter_bloc

  • 仓库:**felangel/bloc**。
  • **bloc 包**:lib/src/bloc.dartBloc 基类、on<Event>emitStream 管道。
  • **flutter_bloc 包**:bloc_builder.dartbloc_listener.dart — 如何把 Stream 接到 Widget 树。

10.4 Flutter 框架层(通用基础)

  • flutter/packages/flutter/lib/src/widgets/framework.dart**ElementInheritedElement** 更新机制。
  • inherited_model.dartnotification_listener.dart — 与自定义状态传播相关时可查。

10.5 阅读方法建议

  1. 先在你自己的 Demo 里 打一个断点,从 Consumer / ref.watch / BlocBuilderbuild 跟进去。
  2. 对照本文「原理要点」只读一条主路径,不要一上来通读全仓库。
  3. 版本以 **pubspec.lock** 为准,避免文档与旧版 API 不一致。

小结

没有「唯一正确」的库:小项目用内置 + Provider 往往足够;大项目更常见 RiverpodBloc 与清晰分层结合。先扫一眼 第二节 里的观察者、Pub/Sub、DI、命令等表述,再对照 InheritedWidgetListenableStream 三条技术线,读各库 API 与源码会省力很多。若你后续锁定某一库做深度拆解,可以在此基础上单独成文(例如只讲 Bloc 的并发与 emit 规则)。

React / Flutter 状态管理

由浅入深,从基本概念到原理与源码,再到示例与实际项目应用案例,系统梳理两大主流框架中的状态管理方案

一、状态管理基础概念

1.1 什么是状态(State)?

状态是驱动 UI 变化的数据。当状态改变时,界面随之更新,形成「数据驱动视图」的声明式模式。

1
2
3
4
状态 ──► 视图
▲ │
│ ▼
└── 用户交互 / 网络请求 / 定时器等

1.2 状态的分类

类型 作用域 典型场景 生命周期
本地状态 单组件 输入框内容、展开/折叠、选中项 跟随组件
共享状态 多组件 用户信息、主题、购物车 需要提升或全局管理
服务端状态 与后端同步 API 数据、缓存 异步、需缓存策略

1.3 为什么需要状态管理?

随着应用复杂度上升,会出现:

  • 状态提升导致 props 层层传递(prop drilling)
  • 状态分散导致难以追踪和调试
  • 重复请求缓存失效等数据一致性问题

状态管理方案的目标:集中、可预测、易维护


二、React 状态管理

2.1 内置方案概览

方案 适用场景 特点
useState 本地状态 简单、轻量
useReducer 复杂本地状态 可预测、易测试
Context API 跨层级共享 官方内置、易造成不必要的重渲染

2.2 useState:最简单的本地状态

1
2
3
4
5
6
7
8
9
10
11
12
function Counter() {
const [count, setCount] = useState(0);

return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>+1</button>
{/* 函数式更新,避免闭包陷阱 */}
<button onClick={() => setCount(prev => prev + 1)}>+1 (安全)</button>
</div>
);
}

惰性初始化:初始值可以是函数,仅在首次渲染执行。

1
const [state, setState] = useState(() => expensiveComputation());

2.3 useReducer:复杂状态的 reducer 模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function reducer(state, action) {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
case 'decrement':
return { count: state.count - 1 };
default:
return state;
}
}

function Counter() {
const [state, dispatch] = useReducer(reducer, { count: 0 });

return (
<div>
<span>{state.count}</span>
<button onClick={() => dispatch({ type: 'increment' })}>+</button>
<button onClick={() => dispatch({ type: 'decrement' })}>-</button>
</div>
);
}

2.4 Context API:跨层级共享状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const ThemeContext = createContext('light');

function App() {
const [theme, setTheme] = useState('light');
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
<Page />
</ThemeContext.Provider>
);
}

function Page() {
const { theme } = useContext(ThemeContext);
return <div className={theme}>...</div>;
}

注意:Provider 的 value 变化会导致所有 useContext 的消费者重渲染,需配合 useMemo 或拆分 Context 优化。

2.5 Redux / Redux Toolkit:全局状态管理

Redux 采用单向数据流View → Action → Reducer → Store → View

1
2
3
4
5
┌─────────┐   dispatch    ┌─────────┐   reduce    ┌────────┐
│ View │ ───────────► │ Action │ ─────────► │ Store │
└─────────┘ └─────────┘ └────────┘
▲ │
└──────────────── subscribe ─────────────────────┘

Redux Toolkit 示例(官方推荐写法):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// store/counterSlice.js
import { createSlice } from '@reduxjs/toolkit';

const counterSlice = createSlice({
name: 'counter',
initialState: { value: 0 },
reducers: {
increment: state => { state.value += 1; },
decrement: state => { state.value -= 1; },
incrementByAmount: (state, action) => {
state.value += action.payload;
},
},
});

export const { increment, decrement, incrementByAmount } = counterSlice.actions;
export default counterSlice.reducer;
1
2
3
4
5
6
7
8
9
10
// 组件中使用
import { useDispatch, useSelector } from 'react-redux';
import { increment } from './store/counterSlice';

function Counter() {
const count = useSelector(state => state.counter.value);
const dispatch = useDispatch();

return <button onClick={() => dispatch(increment())}>{count}</button>;
}

2.6 Zustand:轻量级全局状态

Zustand 基于 Hooks,API 简洁,无 Provider 包裹。

1
2
3
4
5
6
7
8
9
10
11
12
import { create } from 'zustand';

const useStore = create((set) => ({
count: 0,
increment: () => set(state => ({ count: state.count + 1 })),
decrement: () => set(state => ({ count: state.count - 1 })),
}));

function Counter() {
const { count, increment } = useStore();
return <button onClick={increment}>{count}</button>;
}

选择器优化:只订阅需要的字段,避免无关更新。

1
const count = useStore(state => state.count); // 仅 count 变化时重渲染

2.7 React 状态管理原理浅析

useState 的链表结构

React 内部用链表存储 Hooks。每个 Hook 对应链表中的一个节点,通过 FibermemoizedState 串联。

1
2
3
Fiber.memoizedState → Hook1 → Hook2 → Hook3 → ...

[state, setState]

这就是为什么 Hooks 必须在顶层调用、不能放在条件/循环中:链表顺序必须稳定。

setState 的批处理(Batching)

React 18 默认对所有更新进行自动批处理,多次 setState 会合并为一次渲染。

1
2
3
4
5
function handleClick() {
setCount(c => c + 1);
setFlag(f => !f);
// 仅触发一次重渲染
}

三、Flutter 状态管理

3.1 方案概览

方案 官方/社区 适用场景 特点
setState 内置 本地状态 简单,整组件重建
InheritedWidget 内置 跨层级共享 底层基础,一般不直接使用
Provider 官方推荐 中小型应用 基于 InheritedWidget,易上手
Riverpod 社区主流 中大型应用 编译期安全、可测试、无 context
Bloc 社区 复杂业务逻辑 事件驱动、可预测、适合团队
GetX 社区 快速开发 全能型,状态+路由+依赖注入

3.2 setState:最简单的本地状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Counter extends StatefulWidget {
@override
_CounterState createState() => _CounterState();
}

class _CounterState extends State<Counter> {
int _count = 0;

void _increment() {
setState(() {
_count++;
});
}

@override
Widget build(BuildContext context) {
return Column(
children: [
Text('$_count'),
ElevatedButton(onPressed: _increment, child: Text('+1')),
],
);
}
}

原理setState 会标记当前 Element 为脏,在下一帧触发 build 重建子树。

3.3 Provider:官方推荐方案

Provider 基于 InheritedWidget,通过 context.watch<T>() 监听变化并重建。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 1. 定义 Model(继承 ChangeNotifier)
class CounterModel extends ChangeNotifier {
int _count = 0;
int get count => _count;

void increment() {
_count++;
notifyListeners(); // 通知监听者
}
}

// 2. 在根节点提供
void main() {
runApp(
ChangeNotifierProvider(
create: (_) => CounterModel(),
child: MyApp(),
),
);
}

// 3. 在子组件使用
class CounterPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final counter = context.watch<CounterModel>();
return Text('${counter.count}');
}
}

多种 Provider 类型

类型 用途
Provider 不可变值
ChangeNotifierProvider 可变、需 notifyListeners
FutureProvider 异步数据
StreamProvider 流数据
MultiProvider 组合多个 Provider

3.4 Riverpod:下一代状态管理

Riverpod 无 BuildContext 依赖,支持编译期类型安全、易于测试和复用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 1. 定义 Provider
final counterProvider = StateNotifierProvider<CounterNotifier, int>((ref) {
return CounterNotifier();
});

class CounterNotifier extends StateNotifier<int> {
CounterNotifier() : super(0);
void increment() => state++;
}

// 2. 在 runApp 外包一层 ProviderScope
void main() {
runApp(ProviderScope(child: MyApp()));
}

// 3. 在组件中使用(无需 context)
class CounterPage extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final count = ref.watch(counterProvider);
return ElevatedButton(
onPressed: () => ref.read(counterProvider.notifier).increment(),
child: Text('$count'),
);
}
}

ref 的三大方法

方法 作用
ref.watch() 监听变化,值变化时重建
ref.read() 一次性读取,不监听
ref.listen() 监听变化并执行副作用,不重建

3.5 Bloc:事件驱动架构

Bloc 将 UI 与业务逻辑解耦,通过 Event → Bloc → State 的流程管理状态。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 1. 定义 Event 和 State
abstract class CounterEvent {}
class Increment extends CounterEvent {}
class Decrement extends CounterEvent {}

class CounterState {
final int count;
CounterState(this.count);
}

// 2. 实现 Bloc
class CounterBloc extends Bloc<CounterEvent, CounterState> {
CounterBloc() : super(CounterState(0)) {
on<Increment>((event, emit) => emit(CounterState(state.count + 1)));
on<Decrement>((event, emit) => emit(CounterState(state.count - 1)));
}
}

// 3. 在 UI 中使用
BlocProvider(
create: (_) => CounterBloc(),
child: BlocBuilder<CounterBloc, CounterState>(
builder: (context, state) {
return Text('${state.count}');
},
),
)

3.6 Flutter 状态管理原理浅析

setState 与 Element 树

1
2
3
4
5
6
7
8
9
10
setState() 被调用


标记 Element 为 dirty


下一帧 SchedulerBinding 触发 build


Element.rebuild() → State.build()

InheritedWidget 与依赖收集

InheritedWidget 通过 context.dependOnInheritedWidgetOfExactType<T>() 建立「依赖关系」。当 InheritedWidget 更新时,依赖它的 Element 会被标记为脏并重建。

Provider 的 notifyListeners() 会触发 InheritedWidget 的更新,从而通知所有 context.watch 的消费者。


四、React vs Flutter 状态管理对比

4.1 概念映射

概念 React Flutter
本地状态 useState setState
复杂本地状态 useReducer 自建 StatefulWidget + 内部逻辑
跨层级共享 Context InheritedWidget / Provider
全局 Store Redux / Zustand Provider / Riverpod / Bloc
选择器/按需订阅 useSelector / useStore(selector) context.select / ref.watch(provider.select())

4.2 设计哲学差异

维度 React Flutter
更新粒度 组件级,虚拟 DOM diff Widget 树重建,Element 复用
数据流 单向(Redux)或自由(Zustand) 多为单向,Bloc 强调事件流
依赖注入 通过 props / Context 通过 context / ref(Riverpod)
服务端状态 React Query / SWR 等 Riverpod 的 FutureProvider、flutter_bloc 等

五、源码层面的理解

5.1 React useState 的调度

React 的 setState 会调用 dispatchSetState,将更新放入 updateQueue,由调度器(Scheduler)在合适的时机批量处理,触发 rendercommit

1
2
3
4
5
6
// 简化流程
setState(newState)
enqueueUpdate(fiber, update)
scheduleUpdateOnFiber(fiber)
→ performConcurrentWorkOnRoot / performSyncWorkOnRoot
→ commitRoot

5.2 Flutter ChangeNotifier 与 Listenable

ChangeNotifier 继承 Listenable,内部维护 _listeners 列表。notifyListeners() 遍历并调用所有监听者。

1
2
3
4
5
6
// 简化逻辑
void notifyListeners() {
for (final listener in _listeners) {
listener(); // 触发 Consumer 等重建
}
}

ProviderInheritedProvideraddListenerChangeNotifier,当 notifyListeners 被调用时,触发自身 updateShouldNotify 并重建子树。


六、实际项目应用案例

6.1 案例一:电商购物车(React + Zustand)

需求:跨页面购物车数量、增删改、持久化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// store/cartStore.js
import { create } from 'zustand';
import { persist } from 'zustand/middleware';

export const useCartStore = create(
persist(
(set) => ({
items: [],
addItem: (product, qty = 1) =>
set((state) => ({
items: state.items.some((i) => i.id === product.id)
? state.items.map((i) =>
i.id === product.id ? { ...i, qty: i.qty + qty } : i
)
: [...state.items, { ...product, qty }],
})),
removeItem: (id) =>
set((state) => ({ items: state.items.filter((i) => i.id !== id) })),
totalCount: (state) => state.items.reduce((sum, i) => sum + i.qty, 0),
}),
{ name: 'cart-storage' }
)
);

// Header 中只订阅 totalCount,避免整 store 变化导致重渲染
const totalCount = useCartStore((s) =>
s.items.reduce((sum, i) => sum + i.qty, 0)
);

6.2 案例二:用户认证流(Flutter + Riverpod)

需求:登录态、token 刷新、路由守卫。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// providers/auth_provider.dart
final authStateProvider = StateNotifierProvider<AuthNotifier, AsyncValue<User?>>((ref) {
return AuthNotifier(ref);
});

class AuthNotifier extends StateNotifier<AsyncValue<User?>> {
AuthNotifier(this.ref) : super(const AsyncValue.loading()) {
_init();
}
final Ref ref;

Future<void> _init() async {
final token = await storage.getToken();
if (token == null) {
state = const AsyncValue.data(null);
return;
}
state = const AsyncValue.loading();
state = await AsyncValue.guard(() => api.getCurrentUser());
}

Future<void> login(String email, String pwd) async {
state = const AsyncValue.loading();
state = await AsyncValue.guard(() => api.login(email, pwd));
}

void logout() {
storage.clearToken();
state = const AsyncValue.data(null);
}
}

// 路由守卫:根据 authState 跳转登录页或首页
ref.listen(authStateProvider, (prev, next) {
next.whenData((user) {
if (user == null) navigator.pushReplacement(LoginRoute());
});
});

6.3 案例三:列表筛选与分页(React + Redux Toolkit + RTK Query)

需求:筛选条件、分页、缓存、乐观更新。

1
2
3
4
5
6
7
8
// 使用 RTK Query 管理服务端状态
const { data, isLoading, refetch } = useGetProductsQuery({
page: currentPage,
category: selectedCategory,
});

// 本地筛选状态用 Redux 或 useState 均可
const [filters, setFilters] = useState({ category: '', sort: 'default' });

6.4 案例四:主题与多语言(Flutter + Provider)

需求:亮/暗主题、中英文切换,全局生效。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 使用 MultiProvider 组合
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => ThemeModel()),
ChangeNotifierProvider(create: (_) => LocaleModel()),
],
child: MyApp(),
),
);

// 任意子组件
final theme = context.watch<ThemeModel>();
final locale = context.watch<LocaleModel>();

七、选型建议

场景 React 推荐 Flutter 推荐
小项目/原型 useState + Context setState + Provider
中大型项目 Redux Toolkit / Zustand Riverpod / Bloc
强类型、可测试 Redux + TypeScript / Zustand Riverpod
复杂业务流、事件驱动 Redux / XState Bloc
服务端状态 React Query / SWR Riverpod FutureProvider / dio + 自封装

八、总结

  • React:从 useState 起步,全局状态优先考虑 Redux ToolkitZustand,服务端状态用 React Query 等。
  • Flutter:从 setState 起步,共享状态用 Provider 入门,进阶用 RiverpodBloc
  • 选型时关注:团队熟悉度项目规模可测试性与框架生态的契合度

由浅入深掌握上述方案后,可以根据具体业务灵活组合,构建可维护、可扩展的状态管理体系。