Flutter状态管理简化插件bloc_ease的使用
Flutter状态管理简化插件bloc_ease的使用
bloc_ease
是一个Dart库,旨在通过使用typedefs代替定义状态类来解决 flutter_bloc
中样板代码的问题。以下是关于如何使用 bloc_ease
的详细指南。
目录
问题及解决方案
解决的问题
- 重复编写相同类型的状态:对于每个 Bloc/Cubit(初始、加载、成功、失败)。
- 重写
==
和hashCode
:或使用 Equatable 包为所有状态。 - 处理不需要的所有状态:即使只需要成功状态。
- 返回相同的Widget:例如
ProgressIndicator
用于加载状态。 - 管理
buildWhen
:以避免处理所有状态。 - 采用不良实践:如使用单个状态类而不是继承。
- 管理多个状态:由于样板代码的存在。
提供的解决方案
- 消除编写状态类的需求:利用泛型(如
SucceedState<Auth>
vsSucceedState<User>
)。 - 全局处理常见状态:在UI中自动处理初始、加载和失败状态。
- 提供构建器:以类型安全的方式提供成功对象,并自主处理其他状态。
- 使用typedefs:轻松区分状态(如
typedef AuthSucceedState = SucceedState<Auth>
),并提供了IntelliJ和VSCode的代码片段。
如何使用
步骤1:配置BlocEaseStateWidgetProvider
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return BlocEaseStateWidgetProvider(
initialStateBuilder: () => const Placeholder(),
loadingStateBuilder: ([progress]) => const Center(child: CircularProgressIndicator()),
failureStateBuilder: ([exceptionObject, failureMessage]) => Center(child: Text(failureMessage ?? 'Oops something went wrong!')),
child: MaterialApp(
//...
),
);
}
}
步骤2:创建Bloc/Cubit
使用快捷键 bloceasebloc
或 bloceasecubit
创建基于需求的Bloc或Cubit。此模板需要编辑两个名称:
- Cubit名称 -> UserCubit
- 成功对象 -> User(这是从Bloc/Cubit的成功状态预期的对象)
import 'package:bloc_ease/bloc_ease.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
typedef UserState = BlocEaseState<User>; // Success Object
typedef UserInitialState = InitialState<User>;
typedef UserLoadingState = LoadingState<User>;
typedef UserSucceedState = SucceedState<User>;
typedef UserFailedState = FailedState<User>;
typedef UserBlocBuilder = BlocBuilder<UserCubit, UserState>;
typedef UserBlocListener = BlocListener<UserCubit, UserState>;
typedef UserBlocConsumer = BlocConsumer<UserCubit, UserState>;
typedef UserBlocEaseBuilder = BlocEaseStateBuilder<UserCubit, User>;
typedef UserBlocEaseListener = BlocEaseStateListener<UserCubit, User>;
typedef UserBlocEaseConsumer = BlocEaseStateConsumer<UserCubit, User>;
class UserCubit extends Cubit<UserState> {
UserCubit(this.userRepo) : super(const UserInitialState());
final UserRepo userRepo;
void fetchUser() async {
emit(const UserLoadingState());
try {
final user = await userRepo.fetchUser();
emit(UserSucceedState(user));
} catch (e) {
emit(UserFailedState('Failed to fetch user', e));
}
}
}
步骤3:在UI中使用<CubitName>BlocEaseBuilder
class SomeWidget extends StatelessWidget {
const SomeWidget({super.key});
@override
Widget build(BuildContext context) {
return UserBlocEaseBuilder(
succeedBuilder: (user) => SomeOtherWidget(user),
);
}
}
示例代码
获取用户详情
获取用户通常需要4种状态:
- 初始状态 - 当未登录时
- 加载状态 - 当获取进行中
- 成功状态 - 当成功获取时
- 失败状态 - 用户不可用或获取失败
// 定义Cubit
class UserCubit extends Cubit<UserState> {
UserCubit(this.userRepo) : super(const UserInitialState());
final UserRepo userRepo;
void fetchUser() async {
emit(const UserLoadingState());
try {
final user = await userRepo.fetchUser();
emit(UserSucceedState(user));
} catch (e) {
emit(UserFailedState('Failed to fetch user', e));
}
}
}
// UI部分
class UserDetailPage extends StatelessWidget {
const UserDetailPage({super.key});
@override
Widget build(BuildContext context) {
return UserBlocEaseBuilder(
succeedBuilder: (user) => UserDetailsWidget(user),
);
}
}
模板
IntelliJ 和 Android Studio
复制模板后,在IntelliJ/Android studio设置中添加Live Templates,创建新的模板组为BlocEase并粘贴模板。
VSCode
复制模板后,在VSCode中按 Cmd(Ctrl) + Shift + P,选择 “Snippets: Configure User Snippets”,然后在dart.json中粘贴。
技巧与窍门
使用BlocEaseListener和BlocEaseConsumer
class BlocEaseListenerExampleWidget extends StatelessWidget {
const BlocEaseListenerExampleWidget({super.key});
@override
Widget build(BuildContext context) {
return UserBlocEaseListener(
succeedListener: (user) {
// 处理成功状态
},
child: // 子组件
);
}
}
class BlocEaseConsumerExampleWidget extends StatelessWidget {
const BlocEaseConsumerExampleWidget({super.key});
@override
Widget build(BuildContext context) {
return UserBlocEaseConsumer(
succeedBuilder: (user) => SomeWidget(user),
child: // 子组件
);
}
}
测试
blocTest<UserCubit, UserState>(
'emits UserSucceedState after fetching user',
setUp: () {
when(repo.fetchUser).thenAnswer((_) async => mockUser);
},
build: () => UserCubit(repository: repo),
act: (cubit) => cubit.fetchUser(),
expect: () => UserSucceedState(mockUser),
verify: (_) => verify(repository.fetchUser).called(1),
);
以上是关于 bloc_ease
插件的详细介绍和使用方法,希望对您有所帮助!如果有任何问题或建议,请随时联系我。
更多关于Flutter状态管理简化插件bloc_ease的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter状态管理简化插件bloc_ease的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是一个关于如何在Flutter项目中使用bloc_ease
插件来简化状态管理的代码案例。bloc_ease
是一个旨在简化Bloc状态管理库使用的辅助插件。下面是一个简单的示例,展示如何集成和使用bloc_ease
。
1. 添加依赖
首先,在你的pubspec.yaml
文件中添加bloc
和bloc_ease
的依赖:
dependencies:
flutter:
sdk: flutter
bloc: ^8.0.0
flutter_bloc: ^8.0.0
bloc_ease: ^0.1.0 # 确保版本号是最新的
然后运行flutter pub get
来安装依赖。
2. 创建Bloc和Event
假设我们有一个简单的计数器应用,我们需要一个计数器事件和一个计数器状态。
counter_event.dart
import 'package:equatable/equatable.dart';
abstract class CounterEvent extends Equatable {
const CounterEvent();
@override
List<Object?> get props => [];
}
class IncrementEvent extends CounterEvent {}
class DecrementEvent extends CounterEvent {}
counter_state.dart
import 'package:equatable/equatable.dart';
class CounterState extends Equatable {
final int count;
const CounterState({required this.count});
@override
List<Object?> get props => [count];
CounterState copyWith({int? count}) {
return CounterState(count: count ?? this.count);
}
}
3. 创建Bloc
使用bloc_ease
来简化Bloc的创建。
counter_bloc.dart
import 'package:bloc/bloc.dart';
import 'package:bloc_ease/bloc_ease.dart';
import 'counter_event.dart';
import 'counter_state.dart';
part 'counter_bloc.g.dart';
@Cubit(states: [CounterState], initialState: CounterState(count: 0))
class CounterBloc extends _$CounterBloc with _$CounterBlocEaseMixin {
@override
void on<T extends CounterEvent>(_Event event) {
return when(
event is IncrementEvent, () => emit(state.copyWith(count: state.count + 1)),
event is DecrementEvent, () => emit(state.copyWith(count: state.count - 1)),
);
}
}
运行flutter pub run build_runner build
来生成counter_bloc.g.dart
文件。
4. 使用BlocProvider
在你的主应用文件中使用BlocProvider
来提供Bloc实例。
main.dart
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'counter_bloc.dart';
import 'counter_page.dart';
void main() {
runApp(
BlocProvider<CounterBloc>(
create: (_) => CounterBloc(),
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: CounterPage(),
);
}
}
5. 创建UI组件
counter_page.dart
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'counter_bloc.dart';
class CounterPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Counter')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'You have pushed the button this many times:',
),
BlocBuilder<CounterBloc, CounterState>(
builder: (context, state) {
return Text(
'${state.count}',
style: Theme.of(context).textTheme.headline4,
);
},
),
],
),
),
floatingActionButton: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
FloatingActionButton(
onPressed: () => context.read<CounterBloc>().add(IncrementEvent()),
tooltip: 'Increment',
child: Icon(Icons.add),
),
SizedBox(height: 10),
FloatingActionButton(
onPressed: () => context.read<CounterBloc>().add(DecrementEvent()),
tooltip: 'Decrement',
child: Icon(Icons.remove),
),
],
),
);
}
}
总结
以上代码展示了如何使用bloc_ease
来简化Bloc状态管理。通过@Cubit
注解和_$BlocEaseMixin
,我们可以更方便地定义和处理Bloc事件和状态。希望这个示例能帮助你更好地理解如何在Flutter项目中使用bloc_ease
。