Gic*_*ica 1 dart flutter bloc flutter-bloc
我想实现什么目标?
我正在使用Flutter Bloc库作为我的身份验证组件。在登录页面内,我有一些文本字段,例如用户名/密码,我也将与其他页面共享这些文本字段,例如注册页面、忘记密码、更改密码等。基本上,遵循DRY原则。
每个页面(注册、登录、忘记密码等)都有自己的 Bloc 组件。
我的问题 是我找不到将小部件与 Bloc 分离的方法。我希望能够根据使用的页面在有状态小部件中传递任何 BLoc 组件。
为了理解上面写的内容,让我们看一下我的代码。
login.dart登录页面构建方法中的一段代码。
Widget _loginForm(){
return BlocListener<LoginBloc, LoginState>(
listener: (context, state) {
final status = state.formStatus;
if (status is SubmissionFailed) {
...
}
},
child: Form(
key: _formKey,
child: Column(
children: [
// The reusable widget: Email input field.
BlocBuilder<LoginBloc, LoginState>(
builder:(context, state){
return emailInputField(context, state);
}
),
...
Run Code Online (Sandbox Code Playgroud)
现在让我们看一下emailInputField小部件
Widget emailInputField(BuildContext context, dynamic state) {
return TextFormField(
validator: (value) =>
state.isValidEmail ? null : 'Please input a valid email',
onChanged: (value) =>
// HERE - I want to decouple this widget from "LoginBloc".
context.read<LoginBloc>().add(LoginUsernameChanged(username: value)),
labelText: 'Email',
...
);
}
Run Code Online (Sandbox Code Playgroud)
login_bloc.dart登录 Bloc
class LoginBloc extends Bloc<BaseEvent, LoginState>{
LoginBloc() : super(LoginState());
@override
Stream<LoginState> mapEventToState(BaseEvent event) async*{
yield* event.handleEvent(state);
}
}
Run Code Online (Sandbox Code Playgroud)
以及登录事件类,用于全面了解login_event.dart
abstract class LoginEvent extends BaseEvent {
AuthenticationService authService = GetIt.I.get<AuthenticationService>();
}
// Event 1
class LoginUsernameChanged extends LoginEvent {
final String username;
LoginUsernameChanged({this.username});
@override
Stream<LoginState> handleEvent(BaseState state) async* {
// Dart style down-casting...
LoginState loginState = state;
yield loginState.copyWith(username: username);
}
}
Run Code Online (Sandbox Code Playgroud)
基本事件.dart
abstract class BaseEvent {
Stream<BaseState> handleEvent(BaseState state);
}
Run Code Online (Sandbox Code Playgroud)
再说一次,有没有办法将这种观点与 BLoc 脱钩?我希望读完本文后我的问题有意义。
聚苯乙烯
为了让事情变得更简单,我想到的一个想法是保留一个 Bloc 组件,该组件将处理一组相关的输入字段(密码/用户名),然后像我在调用时在login.dart页面中所做的那样传递不同的状态电子邮件输入小部件。
我要做的就是将小部件与块完全分离。不要采用 blocstate并使用bloc.add,而是创建可以使用任何参数填充的依赖项。
在您的示例中,您将拥有:
Widget emailInputField({
required BuildContext context,
required bool isValidEmail,
required void Function(String?) onChange,
}) {
return TextFormField(
validator: (value) => isValidEmail ? null : 'Please input a valid email',
onChanged: onChange,
labelText: 'Email',
...
);
}
Run Code Online (Sandbox Code Playgroud)
然后您可以emailInputField与任何您想要的块一起使用。或者任何与此相关的状态管理库。
对于您的示例,这将给出:
Widget _loginForm(){
return BlocListener<LoginBloc, LoginState>(
listener: (context, state) {
final status = state.formStatus;
if (status is SubmissionFailed) {
...
}
},
child: Form(
key: _formKey,
child: Column(
children: [
// The reusable widget: Email input field.
BlocBuilder<LoginBloc, LoginState>(
builder:(context, state){
return emailInputField(
context: context,
isValidEmail: state.isValidEmail,
onChanged: (value) => context.read<LoginBloc>().add(LoginUsernameChanged(username: value))
);
}
),
...
Run Code Online (Sandbox Code Playgroud)