由浅入深,从基本概念到源码原理,再到实战案例,系统梳理 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 Components 与 Client 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
| async function Page() { const data = await fetchFromDB(); return ( <Layout> <StaticContent data={data} /> <InteractiveCart /> {/* Client Component,内部用 useState */} </Layout> ); }
'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
| '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 树。状态变化触发 setState 或 notifyListeners,进而重建 Widget。
4.2 内置方案
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'), )
|
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
- KVO:
observe(_: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) } }
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
| val repository = Repositories.repositoryWithInitialValue(initialData) .observe() .onUpdatesPerLoop() .getFrom { fetchFromNetwork() } .compile()
repository.addUpdatable(updatable)
|
注意: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() }
|
6.3.4 配置变更保留:rememberSaveable
1 2
| var count by rememberSaveable { mutableStateOf(0) }
|
七、鸿蒙: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 系统追踪状态读取:
mutableStateOf 创建 SnapshotMutableState
- 读取
state.value 时,当前 Composable 的「重组作用域」会记录对该 state 的依赖
- 写入
state.value = x 时,Compose 标记依赖该 state 的作用域需要重组
- 重组时重新执行对应 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
| 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 最佳实践
- 最小化状态:能推导的不要存储,用
useMemo / computed / getter
- 状态提升:当多组件需要共享时,提升到共同祖先
- 不可变更新:避免直接修改,使用
setState/copy/扩展运算符
- 副作用清理:
useEffect 清理、Disposable.dispose、viewModelScope
- 服务端状态分离:与 UI 状态区分,用专门库(React Query 等)管理
- 类型安全: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 |
参考资源