使用 Bloc 重用小部件
Reusing widgets with Bloc
我想达到什么目的?
我正在为我的身份验证组件使用 Flutter BLoc 库。在登录页面内,我有一些文本字段,如 username/password,我也将与其他页面共享,例如注册页面、忘记密码、更改密码等。基本上,遵循 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);
}
),
...
现在让我们来看看 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',
...
);
}
login_bloc.dart 登录区
class LoginBloc extends Bloc<BaseEvent, LoginState>{
LoginBloc() : super(LoginState());
@override
Stream<LoginState> mapEventToState(BaseEvent event) async*{
yield* event.handleEvent(state);
}
}
和登录事件class,以获得完整图片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);
}
}
base_event.dart
abstract class BaseEvent {
Stream<BaseState> handleEvent(BaseState state);
}
再一次,有没有办法将这种观点与 BLoc 分离?
我希望阅读本文后我的问题有意义。
P.S
为了让事情变得更简单,我想到的一个想法是保留一个单一的 Bloc 组件来处理一组相关的输入字段 (password/username),然后像我在login.dart 调用 emailInput 小部件时的页面。
我要做的是将小部件与 bloc 完全分离。不要采用 bloc state
并使用 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',
...
);
}
然后您可以将 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))
);
}
),
...
我想达到什么目的?
我正在为我的身份验证组件使用 Flutter BLoc 库。在登录页面内,我有一些文本字段,如 username/password,我也将与其他页面共享,例如注册页面、忘记密码、更改密码等。基本上,遵循 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);
}
),
...
现在让我们来看看 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',
...
);
}
login_bloc.dart 登录区
class LoginBloc extends Bloc<BaseEvent, LoginState>{
LoginBloc() : super(LoginState());
@override
Stream<LoginState> mapEventToState(BaseEvent event) async*{
yield* event.handleEvent(state);
}
}
和登录事件class,以获得完整图片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);
}
}
base_event.dart
abstract class BaseEvent {
Stream<BaseState> handleEvent(BaseState state);
}
再一次,有没有办法将这种观点与 BLoc 分离? 我希望阅读本文后我的问题有意义。
P.S
为了让事情变得更简单,我想到的一个想法是保留一个单一的 Bloc 组件来处理一组相关的输入字段 (password/username),然后像我在login.dart 调用 emailInput 小部件时的页面。
我要做的是将小部件与 bloc 完全分离。不要采用 bloc state
并使用 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',
...
);
}
然后您可以将 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))
);
}
),
...