1. 狀態(tài)管理基礎
1.1 什么是狀態(tài)
在Flutter中,狀態(tài)(State)指的是應用在特定時間點的數(shù)據(jù)快照。這些數(shù)據(jù)可能包括:
- 用戶數(shù)據(jù)(如個人資料、設置偏好)
- 應用數(shù)據(jù)(如產(chǎn)品列表、購物車內(nèi)容)
- UI狀態(tài)(如加載狀態(tài)、表單驗證、按鈕啟用/禁用)
- 導航狀態(tài)(如當前頁面、導航歷史)
狀態(tài)可以分為兩種主要類型:
- 短暫狀態(tài)(Ephemeral State):也稱為UI狀態(tài)或局部狀態(tài),僅影響單個widget
- 應用狀態(tài)(App State):跨多個widget共享的狀態(tài),影響應用的多個部分
1.2 為什么需要狀態(tài)管理
隨著應用復雜性增加,出現(xiàn)了以下挑戰(zhàn):
- 狀態(tài)分散在應用的不同部分
- 組件間需要共享狀態(tài)
- 需要在組件樹不同層級訪問狀態(tài)
- 狀態(tài)變化需要反映到UI上
- 確保狀態(tài)一致性和可預測性
良好的狀態(tài)管理解決方案應該:
- 使狀態(tài)變化可預測
- 減少組件之間的耦合
- 提高代碼可測試性
- 使應用更易于維護和擴展
2. Flutter中的狀態(tài)管理方案
2.1 setState (基礎方案)
最簡單的狀態(tài)管理方式,適用于管理局部UI狀態(tài)。
基本用法
class CounterWidget extends StatefulWidget {
@override
_CounterWidgetState createState() => _CounterWidgetState();
}
class _CounterWidgetState extends State<CounterWidget> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Column(
children: [
Text('計數(shù): $_counter'),
ElevatedButton(
onPressed: _incrementCounter,
child: Text('增加'),
)
],
);
}
}
優(yōu)缺點
優(yōu)點
- 簡單直觀,是Flutter內(nèi)置的解決方案
- 不需要額外的包依賴
- 適合簡單的UI狀態(tài)管理
缺點
- 不適合跨widget共享狀態(tài)
- 可能導致widget重建過多(性能問題)
- 在復雜應用中會導致代碼難以維護
2.2 InheritedWidget
Flutter提供的用于向下傳遞數(shù)據(jù)的內(nèi)置機制,是許多高級狀態(tài)管理方案的基礎。
基本用法
class CounterModel extends InheritedWidget {
final int counter;
final Function incrementCounter;
CounterModel({
required this.counter,
required this.incrementCounter,
required Widget child,
}) : super(child: child);
static CounterModel of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<CounterModel>()!;
}
@override
bool updateShouldNotify(CounterModel oldWidget) {
return counter != oldWidget.counter;
}
}
class CounterProvider extends StatefulWidget {
final Widget child;
CounterProvider({required this.child});
@override
_CounterProviderState createState() => _CounterProviderState();
}
class _CounterProviderState extends State<CounterProvider> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return CounterModel(
counter: _counter,
incrementCounter: _incrementCounter,
child: widget.child,
);
}
}
// 使用
class CounterScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
final counterModel = CounterModel.of(context);
return Column(
children: [
Text('計數(shù): ${counterModel.counter}'),
ElevatedButton(
onPressed: () => counterModel.incrementCounter(),
child: Text('增加'),
),
],
);
}
}
優(yōu)缺點
優(yōu)點
- Flutter核心機制,無需額外依賴
- 提供從上到下的數(shù)據(jù)流
- 當數(shù)據(jù)變化時自動重建依賴的widgets
缺點
- 需要大量樣板代碼
- 組合多個InheritedWidget比較困難
- 不提供狀態(tài)管理,只提供數(shù)據(jù)傳遞
2.3 Provider
在InheritedWidget基礎上構建的狀態(tài)管理庫,是Flutter團隊推薦的方案之一。
基本用法
// 1. 定義數(shù)據(jù)模型
class CounterModel extends ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners();
}
}
// 2. 提供狀態(tài)
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => CounterModel(),
child: MyApp(),
),
);
}
// 3. 消費狀態(tài)
class CounterDisplay extends StatelessWidget {
@override
Widget build(BuildContext context) {
// 方式1:使用Consumer
return Consumer<CounterModel>(
builder: (context, counter, child) {
return Text('計數(shù): ${counter.count}');
},
);
}
}
class CounterIncrement extends StatelessWidget {
@override
Widget build(BuildContext context) {
// 方式2:使用Provider.of
return ElevatedButton(
onPressed: () {
Provider.of<CounterModel>(context, listen: false).increment();
},
child: Text('增加'),
);
}
}
// 多個Provider嵌套
void main() {
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(create: (context) => CounterModel()),
ChangeNotifierProvider(create: (context) => UserModel()),
Provider(create: (context) => SomeService()),
],
child: MyApp(),
),
);
}
Provider的變體
- Provider: 基本的Provider,不會在值變化時重建widget
- ChangeNotifierProvider: 監(jiān)聽ChangeNotifier,當notifyListeners()被調(diào)用時重建widget
- FutureProvider: 提供Future的結果
- StreamProvider: 提供Stream的最新值
- ListenableProvider: 監(jiān)聽Listenable對象,適用于不是ChangeNotifier的情況
- ValueListenableProvider: 專門用于ValueListenable
優(yōu)缺點
優(yōu)點
- 易于學習和使用
- 良好的性能(精確控制重建)
- 與Flutter很好地集成
- 支持依賴注入
- 豐富的文檔和社區(qū)支持
- 由Flutter團隊推薦
缺點
- 復雜應用中可能需要創(chuàng)建大量模型類
- 處理深層次嵌套狀態(tài)需要精心設計
- 狀態(tài)模型之間的依賴需要手動管理
2.4 Riverpod
Provider的進化版,解決了Provider的一些限制。
基本用法
// 1. 定義Provider
final counterProvider = StateNotifierProvider<CounterNotifier, int>((ref) {
return CounterNotifier();
});
class CounterNotifier extends StateNotifier<int> {
CounterNotifier() : super(0);
void increment() => state = state + 1;
}
// 2. 在應用頂層使用ProviderScope
void main() {
runApp(
ProviderScope(
child: MyApp(),
),
);
}
// 3. 使用狀態(tài)
class CounterDisplay extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final count = ref.watch(counterProvider);
return Text('計數(shù): $count');
}
}
class CounterIncrement extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
return ElevatedButton(
onPressed: () {
ref.read(counterProvider.notifier).increment();
},
child: Text('增加'),
);
}
}
Riverpod的特點
- 完全類型安全,沒有運行時錯誤
- 不需要上下文(context)來訪問providers
- 可以在任何地方(甚至在initState外部)訪問providers
- 支持自動釋放未使用的狀態(tài)
- 輕松處理異步狀態(tài)
- 簡化測試
優(yōu)缺點
優(yōu)點
- 解決了Provider的上下文依賴問題
- 提供真正的類型安全
- 更好的異步狀態(tài)處理
- 簡化代碼復用
缺點
- 學習曲線稍陡
- 與Flutter不同的語法(ref vs context)
- 需要特殊widget(ConsumerWidget等)
2.5 BLoC/Cubit
基于流(Stream)的狀態(tài)管理方案,將業(yè)務邏輯與UI分離。
Cubit (簡化的BLoC)
// 1. 定義狀態(tài)
class CounterState {
final int count;
CounterState(this.count);
}
// 2. 創(chuàng)建Cubit
class CounterCubit extends Cubit<CounterState> {
CounterCubit() : super(CounterState(0));
void increment() {
emit(CounterState(state.count + 1));
}
}
// 3. 提供Cubit
void main() {
runApp(
BlocProvider(
create: (context) => CounterCubit(),
child: MyApp(),
),
);
}
// 4. 使用狀態(tài)
class CounterPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: BlocBuilder<CounterCubit, CounterState>(
builder: (context, state) {
return Text('計數(shù): ${state.count}');
},
),
floatingActionButton: FloatingActionButton(
onPressed: () => context.read<CounterCubit>().increment(),
child: Icon(Icons.add),
),
);
}
}
BLoC (完整版)
// 1. 定義事件
abstract class CounterEvent {}
class IncrementEvent extends CounterEvent {}
// 2. 創(chuàng)建BLoC
class CounterBloc extends Bloc<CounterEvent, CounterState> {
CounterBloc() : super(CounterState(0)) {
on<IncrementEvent>((event, emit) {
emit(CounterState(state.count + 1));
});
}
}
// 3. 提供BLoC
void main() {
runApp(
BlocProvider(
create: (context) => CounterBloc(),
child: MyApp(),
),
);
}
// 4. 使用狀態(tài)
class CounterPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: BlocBuilder<CounterBloc, CounterState>(
builder: (context, state) {
return Text('計數(shù): ${state.count}');
},
),
floatingActionButton: FloatingActionButton(
onPressed: () => context.read<CounterBloc>().add(IncrementEvent()),
child: Icon(Icons.add),
),
);
}
}
優(yōu)缺點
優(yōu)點
- 狀態(tài)、事件和業(yè)務邏輯的強分離
- 高度可測試性
- 反應式編程方式
- 復雜狀態(tài)轉(zhuǎn)換的良好處理
缺點
- 較陡峭的學習曲線
- 增加了大量樣板代碼
- 小型應用中可能過于復雜
2.6 Redux
基于單向數(shù)據(jù)流的狀態(tài)管理方案,源自Web開發(fā)。
基本用法
// 1. 定義應用狀態(tài)
class AppState {
final int counter;
AppState({this.counter = 0});
AppState copyWith({int? counter}) {
return AppState(
counter: counter ?? this.counter,
);
}
}
// 2. 定義Action
class IncrementAction {}
// 3. 創(chuàng)建Reducer
AppState reducer(AppState state, dynamic action) {
if (action is IncrementAction) {
return state.copyWith(counter: state.counter + 1);
}
return state;
}
// 4. 創(chuàng)建Store
final store = Store<AppState>(
reducer,
initialState: AppState(),
);
// 5. 提供Store
void main() {
runApp(
StoreProvider<AppState>(
store: store,
child: MyApp(),
),
);
}
// 6. 使用狀態(tài)
class CounterDisplay extends StatelessWidget {
@override
Widget build(BuildContext context) {
return StoreConnector<AppState, int>(
converter: (store) => store.state.counter,
builder: (context, counter) {
return Text('計數(shù): $counter');
},
);
}
}
class CounterIncrement extends StatelessWidget {
@override
Widget build(BuildContext context) {
return StoreConnector<AppState, VoidCallback>(
converter: (store) {
return () => store.dispatch(IncrementAction());
},
builder: (context, callback) {
return ElevatedButton(
onPressed: callback,
child: Text('增加'),
);
},
);
}
}
優(yōu)缺點
優(yōu)點
- 可預測的單向數(shù)據(jù)流
- 集中式狀態(tài)管理
- 良好的調(diào)試能力(時間旅行調(diào)試)
- 中間件支持(處理副作用)
缺點
- 大量樣板代碼
- 較陡峭的學習曲線
- 簡單操作需要多處修改
2.7 GetX
輕量級且功能強大的狀態(tài)管理、路由管理和依賴注入解決方案。
基本用法
// 1. 定義控制器
class CounterController extends GetxController {
var count = 0.obs; // 使用.obs創(chuàng)建可觀察變量
void increment() {
count++; // 自動更新UI
}
}
// 2. 初始化
void main() {
runApp(
GetMaterialApp( // 替換MaterialApp
home: Home(),
),
);
}
// 3. 使用狀態(tài) - 方式1:GetX
class CounterDisplay1 extends StatelessWidget {
final controller = Get.put(CounterController()); // 注入控制器
@override
Widget build(BuildContext context) {
return GetX<CounterController>(
builder: (controller) {
return Text('計數(shù): ${controller.count.value}');
},
);
}
}
// 3. 使用狀態(tài) - 方式2:Obx(更簡潔)
class CounterDisplay2 extends StatelessWidget {
final controller = Get.find<CounterController>(); // 查找已注入的控制器
@override
Widget build(BuildContext context) {
return Obx(() => Text('計數(shù): ${controller.count.value}'));
}
}
// 4. 更新狀態(tài)
class CounterIncrement extends StatelessWidget {
final controller = Get.find<CounterController>();
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: controller.increment,
child: Text('增加'),
);
}
}
優(yōu)缺點
優(yōu)點
- 簡單易用,API簡潔
- 整合路由管理、依賴注入和狀態(tài)管理
- 高性能(只重建需要的widgets)
- 不需要上下文(context)
- 低樣板代碼量
缺點
- 非標準Flutter方法
- 社區(qū)支持不如主流方案
- 架構可能導致濫用全局狀態(tài)
2.8 MobX
基于可觀察對象的狀態(tài)管理庫,源自React生態(tài)系統(tǒng)。
基本用法
// 1. 定義Store
part 'counter_store.g.dart'; // 代碼生成部分
class CounterStore = _CounterStore with _$CounterStore;
abstract class _CounterStore with Store {
@observable
int count = 0;
@computed
bool get isEven => count % 2 == 0;
@action
void increment() {
count++;
}
}
// 2. 創(chuàng)建和提供Store
final counterStore = CounterStore();
// 3. 使用Store
class CounterDisplay extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Observer(
builder: (_) => Column(
children: [
Text('計數(shù): ${counterStore.count}'),
Text('是偶數(shù): ${counterStore.isEven ? "是" : "否"}'),
],
),
);
}
}
class CounterIncrement extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: counterStore.increment,
child: Text('增加'),
);
}
}
優(yōu)缺點
優(yōu)點
- 基于可觀察模式,精確更新
- 計算屬性支持
- 響應式編程體驗
- 與React MobX相似(熟悉React的開發(fā)者易上手)
缺點
- 需要代碼生成
- 需要特殊裝飾器處理
- 學習曲線中等
3. 狀態(tài)管理方案比較
3.1 功能比較
| 特性/方案 | setState | InheritedWidget | Provider | Riverpod | BLoC | Redux | GetX | MobX |
|---|---|---|---|---|---|---|---|---|
| 復雜度 | 低 | 中 | 低-中 | 中 | 高 | 高 | 低 | 中 |
| 學習曲線 | 很淺 | 中等 | 淺 | 中等 | 陡峭 | 陡峭 | 淺 | 中等 |
| 樣板代碼 | 很少 | 多 | 少 | 少 | 多 | 很多 | 很少 | 中等 |
| 性能 | 中等 | 良好 | 良好 | 良好 | 良好 | 良好 | 良好 | 良好 |
| 可測試性 | 低 | 中 | 高 | 高 | 很高 | 很高 | 中 | 高 |
| 社區(qū)支持 | 很高 | 高 | 很高 | 高 | 高 | 中 | 中 | 中 |
| 適合項目規(guī)模 | 小型 | 小-中型 | 小-大型 | 小-大型 | 中-大型 | 中-大型 | 小-大型 | 小-大型 |
| 開發(fā)團隊 | Flutter | Flutter | Flutter社區(qū) | Flutter社區(qū) | Flutter社區(qū) | Flutter社區(qū) | GetX團隊 | Flutter社區(qū) |
3.2 適用場景
- setState: 簡單的組件內(nèi)狀態(tài)管理,原型開發(fā)
- Provider: 中小型應用,需要共享狀態(tài)但不復雜
- Riverpod: 需要更好類型安全和依賴管理的應用
- BLoC/Cubit: 大型應用,有復雜業(yè)務邏輯,團隊協(xié)作
- Redux: 需要嚴格狀態(tài)控制,喜歡函數(shù)式編程
- GetX: 需要快速開發(fā),簡潔代碼,及路由管理
- MobX: 喜歡響應式編程,熟悉MobX從React遷移
4. 狀態(tài)管理最佳實踐
4.1 通用原則
-
基于復雜度選擇工具
- 簡單狀態(tài)使用簡單工具(setState)
- 不要過早優(yōu)化或引入復雜框架
-
狀態(tài)分層
- 區(qū)分UI狀態(tài)和業(yè)務狀態(tài)
- 局部狀態(tài)使用局部解決方案
- 全局狀態(tài)使用全局方案
-
單一數(shù)據(jù)源
- 每個狀態(tài)應該有一個明確的來源
- 避免狀態(tài)重復
-
不可變狀態(tài)
- 不直接修改狀態(tài)
- 創(chuàng)建新狀態(tài)來替換舊狀態(tài)
-
最小化重建
- 只重建依賴變化狀態(tài)的UI部分
- 將大型widget拆分為小部件
4.2 代碼組織
-
關注點分離
- 將UI、業(yè)務邏輯和數(shù)據(jù)訪問分開
- 使用分層架構(UI層、業(yè)務層、數(shù)據(jù)層)
-
模塊化
- 按功能組織代碼,而不是按類型
- 每個模塊包含其UI和狀態(tài)管理
-
依賴注入
- 使用依賴注入降低組件耦合
- 便于測試和替換實現(xiàn)
4.3 常見反模式
-
狀態(tài)過度集中
- 將所有狀態(tài)放在一個巨大的類中
- 導致不必要的重建和性能問題
-
狀態(tài)過度分散
- 沒有合理組織相關狀態(tài)
- 導致狀態(tài)管理混亂,難以維護
-
過早優(yōu)化
- 在不需要復雜解決方案時使用它們
- 增加不必要的學習和開發(fā)成本
-
濫用全局狀態(tài)
- 將應該是局部的狀態(tài)放到全局
- 導致組件緊密耦合
5. 實際案例
5.1 購物車應用(使用Provider)
// 定義產(chǎn)品模型
class Product {
final int id;
final String name;
final double price;
Product({required this.id, required this.name, required this.price});
}
// 購物車模型
class CartModel extends ChangeNotifier {
final List<Product> _items = [];
List<Product> get items => List.unmodifiable(_items);
double get totalPrice =>
_items.fold(0, (sum, product) => sum + product.price);
void add(Product product) {
_items.add(product);
notifyListeners();
}
void removeAt(int index) {
_items.removeAt(index);
notifyListeners();
}
void clear() {
_items.clear();
notifyListeners();
}
}
// 產(chǎn)品目錄模型
class CatalogModel extends ChangeNotifier {
final List<Product> _products = [
Product(id: 1, name: "商品1", price: 10.0),
Product(id: 2, name: "商品2", price: 15.0),
Product(id: 3, name: "商品3", price: 20.0),
];
List<Product> get products => List.unmodifiable(_products);
}
// 應用入口
void main() {
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(create: (context) => CatalogModel()),
ChangeNotifierProvider(create: (context) => CartModel()),
],
child: MyApp(),
),
);
}
// 產(chǎn)品列表頁面
class ProductListPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final catalog = Provider.of<CatalogModel>(context);
final cart = Provider.of<CartModel>(context, listen: false);
return Scaffold(
appBar: AppBar(
title: Text('產(chǎn)品列表'),
actions: [
IconButton(
icon: Icon(Icons.shopping_cart),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => CartPage()),
);
},
),
],
),
body: ListView.builder(
itemCount: catalog.products.length,
itemBuilder: (context, index) {
final product = catalog.products[index];
return ListTile(
title: Text(product.name),
subtitle: Text('¥${product.price}'),
trailing: IconButton(
icon: Icon(Icons.add_shopping_cart),
onPressed: () {
cart.add(product);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('${product.name} 已添加到購物車')),
);
},
),
);
},
),
);
}
}
// 購物車頁面
class CartPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('購物車')),
body: Consumer<CartModel>(
builder: (context, cart, child) {
if (cart.items.isEmpty) {
return Center(child: Text('購物車為空'));
}
return Column(
children: [
Expanded(
child: ListView.builder(
itemCount: cart.items.length,
itemBuilder: (context, index) {
final product = cart.items[index];
return ListTile(
title: Text(product.name),
subtitle: Text('¥${product.price}'),
trailing: IconButton(
icon: Icon(Icons.remove_circle),
onPressed: () {
cart.removeAt(index);
},
),
);
},
),
),
Padding(
padding: const EdgeInsets.all(16.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('總計: ¥${cart.totalPrice}',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
ElevatedButton(
onPressed: () {
// 結賬邏輯
cart.clear();
Navigator.pop(context);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('訂單已完成')),
);
},
child: Text('結賬'),
),
],
),
),
],
);
},
),
);
}
}
5.2 認證應用(使用BLoC)
// 認證狀態(tài)
abstract class AuthState {}
class AuthInitial extends AuthState {}
class AuthLoading extends AuthState {}
class AuthAuthenticated extends AuthState {
final User user;
AuthAuthenticated(this.user);
}
class AuthUnauthenticated extends AuthState {
final String? message;
AuthUnauthenticated([this.message]);
}
// 認證事件
abstract class AuthEvent {}
class LoginEvent extends AuthEvent {
final String username;
final String password;
LoginEvent(this.username, this.password);
}
class LogoutEvent extends AuthEvent {}
// 用戶模型
class User {
final String id;
final String name;
User({required this.id, required this.name});
}
// 認證服務
class AuthService {
Future<User> login(String username, String password) async {
// 模擬網(wǎng)絡請求
await Future.delayed(Duration(seconds: 2));
if (username == 'admin' && password == 'password') {
return User(id: '1', name: 'Admin User');
} else {
throw Exception('用戶名或密碼錯誤');
}
}
Future<void> logout() async {
await Future.delayed(Duration(seconds: 1));
// 清除令牌等
}
}
// 認證BLoC
class AuthBloc extends Bloc<AuthEvent, AuthState> {
final AuthService authService;
AuthBloc(this.authService) : super(AuthInitial()) {
on<LoginEvent>(_onLogin);
on<LogoutEvent>(_onLogout);
}
Future<void> _onLogin(LoginEvent event, Emitter<AuthState> emit) async {
emit(AuthLoading());
try {
final user = await authService.login(event.username, event.password);
emit(AuthAuthenticated(user));
} catch (e) {
emit(AuthUnauthenticated(e.toString()));
}
}
Future<void> _onLogout(LogoutEvent event, Emitter<AuthState> emit) async {
emit(AuthLoading());
try {
await authService.logout();
emit(AuthUnauthenticated());
} catch (e) {
emit(AuthUnauthenticated(e.toString()));
}
}
}
// 應用入口
void main() {
runApp(
BlocProvider(
create: (context) => AuthBloc(AuthService()),
child: MyApp(),
),
);
}
// 主應用
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: BlocBuilder<AuthBloc, AuthState>(
builder: (context, state) {
if (state is AuthAuthenticated) {
return HomePage(user: state.user);
}
return LoginPage();
},
),
);
}
}
// 登錄頁面
class LoginPage extends StatefulWidget {
@override
_LoginPageState createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
final _usernameController = TextEditingController();
final _passwordController = TextEditingController();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('登錄')),
body: BlocConsumer<AuthBloc, AuthState>(
listener: (context, state) {
if (state is AuthUnauthenticated && state.message != null) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(state.message!)),
);
}
},
builder: (context, state) {
return Padding(
padding: EdgeInsets.all(16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextField(
controller: _usernameController,
decoration: InputDecoration(labelText: '用戶名'),
),
TextField(
controller: _passwordController,
decoration: InputDecoration(labelText: '密碼'),
obscureText: true,
),
SizedBox(height: 20),
if (state is AuthLoading)
CircularProgressIndicator()
else
ElevatedButton(
onPressed: () {
context.read<AuthBloc>().add(
LoginEvent(
_usernameController.text,
_passwordController.text,
),
);
},
child: Text('登錄'),
),
],
),
);
},
),
);
}
}
// 主頁
class HomePage extends StatelessWidget {
final User user;
HomePage({required this.user});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('主頁'),
actions: [
IconButton(
icon: Icon(Icons.logout),
onPressed: () {
context.read<AuthBloc>().add(LogoutEvent());
},
),
],
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('歡迎, ${user.name}!', style: TextStyle(fontSize: 24)),
Text('ID: ${user.id}'),
],
),
),
);
}
}
6. 結論
Flutter中的狀態(tài)管理沒有一種通用的最佳解決方案,選擇取決于多種因素:
- 項目規(guī)模和復雜度
- 團隊經(jīng)驗和熟悉度
- 性能需求
- 開發(fā)速度需求
- 代碼可維護性需求