Flutter状态管理副作用处理插件flutter_bloc_side_effect的使用
Flutter状态管理副作用处理插件flutter_bloc_side_effect的使用
标题
Flutter状态管理副作用处理插件flutter_bloc_side_effect的使用
内容
-
动机
- 这个包旨在解决在使用BLoC状态管理开发移动应用时可能遇到的一些问题。这些问题包括: 1 将许多参数放在状态类中只是为了在UI上响应它们。现在可以通过使用单独的状态流来摆脱这一点。 2 发出状态只是因为需要显示toast或执行任何小动作在UI上,即使你的业务逻辑不暗示这种发出。 3 必须连续发出两种不同的状态以在UI上执行某些操作,因为flutter_bloc当前实现故意不监听状态是否为同一类型。
-
副作用特性
- 副作用特性受到side_effect_bloc启发,并且基于原始flutter_bloc的一些新实用工具。 使用它们就像通常一样,但需要提供一个副作用处理器。这些组件如下: 1 BlocBuilder → BlocBuilderWithSideEffects 2 BlocListener → BlocListenerWithSideEffects 3 BlocConsumer → BlocConsumerWithSideEffects。
-
使用说明
- 如果你不需要副作用特性,请使用原生组件在UI上。 但现在必须提供
bloc
参数,因为它被要求。 这是唯一的区别。 这些组件是: 1 BlocBuilder 2 BlocListener 3 BlocConsumer。
- 如果你不需要副作用特性,请使用原生组件在UI上。 但现在必须提供
-
注意
- 一些原始类在这个包中没有出现!这些是: 1 DI相关的(BlocProvider, MultiBlocProvider, RepositoryProvider, MultiRepositoryProvider) 2 Cubit 3 其他(MultiBlocListener, BlocSelector)。
示例代码
import 'package:flutter/material.dart';
import 'package:flutter_bloc_side_effect/flutter_bloc_side_effect.dart';
import 'package:flutter_bloc_side_effect_example/my_bloc.dart';
void main() {
runApp(const App());
}
class App extends StatelessWidget {
const App({super.key});
[@override](/user/override)
Widget build(BuildContext context) {
return const MaterialApp(home: MyView());
}
}
final myBloc = MyBloc();
class MyView extends StatelessWidget {
const MyView({super.key});
[@override](/user/override)
Widget build(BuildContext context) {
return BlocConsumerWithSideEffects<MyBloc, MyState, MySideEffect>(
bloc: myBloc,
sideEffectsListener: (context, sideEffect) {
sideEffect.map(
error: (sideEffect) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(sideEffect.message)),
);
},
);
},
listener: (_, state) => log(state.stateName),
builder: (context, state) {
return Scaffold(
appBar: AppBar(title: Text(state.stateName)),
floatingActionButton: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
FloatingActionButton(
onPressed: () => myBloc.add(const MyEvent.throwError()),
child: const Text('Error'),
),
],
),
);
},
);
}
}
完整示例demo
import 'package:flutter/material.dart';
import 'package:flutter_bloc_side_effect/flutter_bloc_side_effect.dart';
import 'package:flutter_bloc_side_effect_example/my_bloc.dart';
void main() {
runApp(const App());
}
class App extends StatelessWidget {
const App({super.key});
[@override](/user/override)
Widget build(BuildContext context) {
return const MaterialApp(home: MyView());
}
}
final myBloc = MyBloc();
class MyView extends StatelessWidget {
const MyView({super.key});
[@override](/user/override)
Widget build(BuildContext context) {
return BlocConsumerWithSideEffects<MyBloc, MyState, MySideEffect>(
bloc: myBloc,
sideEffectsListener: (context, sideEffect) {
sideEffect.map(
error: ( sideEffect) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(sideEffect.message)),
);
},
);
},
listener: (_, state) => log(state.stateName),
builder: (context, state) {
return Scaffold(
appBar: AppBar(title: Text(state.stateName)),
floatingActionButton: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
FloatingActionButton(
onPressed: () => myBloc.add(const MyEvent.throwError()),
child: const Text('Error'),
),
],
),
);
},
);
}
}
更多关于Flutter状态管理副作用处理插件flutter_bloc_side_effect的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter状态管理副作用处理插件flutter_bloc_side_effect的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
在处理Flutter应用中的状态管理及其副作用时,flutter_bloc
是一个非常流行的库,而 flutter_bloc_side_effect
则是其一个有用的扩展,专门用于处理BLoC(Business Logic Component)中的副作用(如API调用、日志记录、推送通知等)。下面是一个关于如何使用 flutter_bloc_side_effect
的代码示例,演示了如何在BLoC中处理副作用。
1. 添加依赖
首先,确保在你的 pubspec.yaml
文件中添加了 flutter_bloc
和 flutter_bloc_side_effect
的依赖:
dependencies:
flutter:
sdk: flutter
flutter_bloc: ^8.0.0 # 请检查最新版本号
flutter_bloc_side_effect: ^0.1.0 # 请检查最新版本号
2. 创建BLoC和状态
接下来,创建一个简单的BLoC和相关的状态类。例如,我们有一个用于管理用户登录的BLoC。
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_bloc_side_effect/flutter_bloc_side_effect.dart';
// 定义状态
enum LoginStatus { loading, success, failure }
class LoginState {
final LoginStatus status;
final String? message;
LoginState(this.status, this.message);
// 工厂方法创建不同的状态实例
factory LoginState.loading() => LoginState(LoginStatus.loading, null);
factory LoginState.success() => LoginState(LoginStatus.success, "Login successful");
factory LoginState.failure(String message) => LoginState(LoginStatus.failure, message);
}
// 定义事件
class LoginEvent extends Equatable {
final String username;
final String password;
LoginEvent(this.username, this.password);
@override
List<Object?> get props => [username, password];
}
// 创建BLoC
class LoginBloc extends Bloc<LoginEvent, LoginState> with BlocSideEffect<LoginEvent, LoginState> {
LoginBloc() : super(LoginState.loading()) {
on<LoginEvent>((event, emit) async {
emit(state.copyWith(status: LoginStatus.loading));
// 模拟登录API调用
bool isAuthenticated = await authenticateUser(event.username, event.password);
if (isAuthenticated) {
emit(state.copyWith(status: LoginStatus.success));
} else {
emit(state.copyWith(status: LoginStatus.failure, message: "Invalid credentials"));
}
// 添加副作用处理
addSideEffect(effect: (state) async {
if (state.status == LoginStatus.success) {
// 例如,记录登录成功日志
await logSuccess("User ${event.username} logged in successfully");
} else if (state.status == LoginStatus.failure) {
// 例如,发送错误通知
await showErrorNotification("Login failed: ${state.message ?? "Unknown error"}");
}
});
});
}
// 模拟的用户认证函数
Future<bool> authenticateUser(String username, String password) async {
// 这里可以添加实际的API调用逻辑
await Future.delayed(Duration(seconds: 2));
return username == "user" && password == "pass";
}
// 模拟的日志记录函数
Future<void> logSuccess(String message) async {
// 这里可以添加实际的日志记录逻辑
print(message);
}
// 模拟的错误通知函数
Future<void> showErrorNotification(String message) async {
// 这里可以添加实际的通知显示逻辑
print("Notification: $message");
}
}
3. 使用BLoC在UI中
最后,在你的Flutter组件中使用这个BLoC来管理UI状态。
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'login_bloc.dart'; // 假设上面的代码保存在这个文件中
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: BlocProvider(
create: (context) => LoginBloc(),
child: LoginScreen(),
),
);
}
}
class LoginScreen extends StatelessWidget {
final TextEditingController _usernameController = TextEditingController();
final TextEditingController _passwordController = TextEditingController();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Login")),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
TextField(
controller: _usernameController,
decoration: InputDecoration(labelText: "Username"),
),
TextField(
controller: _passwordController,
decoration: InputDecoration(labelText: "Password"),
obscureText: true,
),
SizedBox(height: 20),
BlocButton<LoginBloc, LoginState>(
buildWhen: (previous, current) => current.status == LoginStatus.loading || current.status == LoginStatus.failure,
onPressed: () {
context.read<LoginBloc>().add(LoginEvent(_usernameController.text, _passwordController.text));
},
child: Text("Login"),
),
if (context.select<LoginBloc, LoginStatus>((bloc) => bloc.state.status) == LoginStatus.success)
Text("Login successful!"),
if (context.select<LoginBloc, LoginStatus>((bloc) => bloc.state.status) == LoginStatus.failure)
Text("${context.select<LoginBloc, String?>((bloc) => bloc.state.message ?? "")}"),
],
),
),
);
}
}
在这个示例中,我们创建了一个 LoginBloc
,它处理登录事件,并在状态改变时触发副作用(如日志记录和通知显示)。我们还创建了一个简单的UI来演示如何使用这个BLoC。注意,这个示例中的 authenticateUser
、logSuccess
和 showErrorNotification
函数都是模拟的,你需要根据你的应用需求来实现这些逻辑。