由浅入深,从基本概念到原理与源码,再到示例与实际项目应用案例,系统梳理两大主流框架中的状态管理方案
一、状态管理基础概念 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 优化。
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 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 );
2.7 React 状态管理原理浅析 useState 的链表结构 React 内部用链表 存储 Hooks。每个 Hook 对应链表中的一个节点,通过 Fiber 的 memoizedState 串联。
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 class CounterModel extends ChangeNotifier { int _count = 0 ; int get count => _count; void increment() { _count++; notifyListeners(); } } void main() { runApp( ChangeNotifierProvider( create: (_) => CounterModel(), child: MyApp(), ), ); } 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 final counterProvider = StateNotifierProvider<CounterNotifier, int >((ref) { return CounterNotifier(); }); class CounterNotifier extends StateNotifier <int > { CounterNotifier() : super (0 ); void increment() => state++; } void main() { runApp(ProviderScope(child: MyApp())); } 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 abstract class CounterEvent {}class Increment extends CounterEvent {}class Decrement extends CounterEvent {}class CounterState { final int count; CounterState(this .count); } 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 ))); } } 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 通过 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)在合适的时机批量处理,触发 render 和 commit。
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(); } }
Provider 的 InheritedProvider 会 addListener 到 ChangeNotifier,当 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 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' } ) ); 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 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 ); } } ref.listen(authStateProvider, (prev, next) { next.whenData((user) { if (user == null ) navigator.pushReplacement(LoginRoute()); }); });
需求 :筛选条件、分页、缓存、乐观更新。
1 2 3 4 5 6 7 8 const { data, isLoading, refetch } = useGetProductsQuery ({ page : currentPage, category : selectedCategory, }); 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 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 Toolkit 或 Zustand ,服务端状态用 React Query 等。
Flutter :从 setState 起步,共享状态用 Provider 入门,进阶用 Riverpod 或 Bloc 。
选型时关注:团队熟悉度 、项目规模 、可测试性 、与框架生态的契合度 。
由浅入深掌握上述方案后,可以根据具体业务灵活组合,构建可维护、可扩展的状态管理体系。