【问题标题】:Reusing widgets with Bloc使用 Bloc 重用小部件
【发布时间】:2021-11-15 21:40:36
【问题描述】:

我想实现什么?

我正在为我的身份验证组件使用 Flutter BLoc 库。在登录页面内,我有一些文本字段,例如用户名/密码,我也将与其他页面共享,例如注册页面、忘记密码、更改密码等。基本上,遵循 DRY 原则.

每个页面(注册、登录、忘记密码等)都有自己的 BLoc 组件。

我的问题 我找不到将小部件与 BLoc 分离的方法。我希望能够在有状态小部件中传递任何 BLoc 组件,具体取决于它所使用的页面。

为了理解上面的内容,让我们看看我的代码。

login.dart 来自登录页面的 build 方法的一段代码。

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);
  }

}

还有登录事件类,用于获得完整的图片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 分离? 我希望我的问题在阅读后有意义。

附言

为了让事情变得更简单,我想到的一个想法是保留一个 Bloc 组件,该组件将处理一组相关的输入字段(密码/用户名),然后像我在 login 中所做的那样传递不同的状态.dart 调用 emailInput 小部件时的页面。

【问题讨论】:

    标签: flutter dart bloc flutter-bloc


    【解决方案1】:

    我要做的是将小部件与 bloc 完全分离。不要使用statebloc.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))
                    );
                  }
                ),
                ...
    

    【讨论】:

    • 这是个好主意,但是如何将新值传递给 onChange 函数?
    • 查看我的更新答案
    猜你喜欢
    • 2019-04-28
    • 2019-12-10
    • 1970-01-01
    • 2020-02-19
    • 2021-12-05
    • 1970-01-01
    • 2022-11-16
    • 2021-10-22
    • 2021-01-18
    相关资源
    最近更新 更多