【发布时间】:2021-03-09 23:04:00
【问题描述】:
对于一个非常简单的页面,我真的很难将我的 MVVM 模式转换为带有 flutter_bloc 的 bloc 模式。我最直接关心的是我应该将执行副作用的函数放在哪里?
我有这个BlocListener 在从块发出状态时执行副作用,并调用 ViewModel:
BlocListener<LoggedOutNicknameCubit, LoggedOutNicknameState>(
listener: (context, state) {
state.maybeWhen(
submitted: () => loggedOutNickNameViewModel.submitPressed(context),
orElse: () {});
})
是否可以只将 ViewModel 注入到视图中,其中包含执行副作用的函数,这样我就不必直接在视图中执行副作用,因此我可以将业务逻辑与视图分离?我是否也可以将可变状态添加到该 ViewModel 中,该状态根本不具有不可变的意义,因此处于从 bloc 发出的“bloc”状态上没有意义?
我不得不说我确实想在很多事情上使用 bloc 但我只是不想将它用于我的表单验证,这只是个人喜好,因为我喜欢内置的表单验证reactive_forms.
我的 ViewModel 包含我的副作用和可变的表单状态,如下所示:
class LoggedOutNickNameViewModel extends VpViewModel {
LoggedOutNickNameViewModel(
this._saveNickNameLocallyUseCase, this._getUserFieldFromLocalUseCase)
: super(null);
FormGroup get form => _form;
String get nickNameKey => _nickNameKey;
FormGroup _form;
final ISaveNickNameLocallyUseCase _saveNickNameLocallyUseCase;
final IGetUserFieldFromLocalUseCase _getUserFieldFromLocalUseCase;
final String _nickNameKey = UserRegistrationFieldKeys.nickName;
@override
void onClose() {
_saveNickNameLocallyUseCase
.invoke(_form.control(_nickNameKey).value as String ?? '');
}
void onCreate() {
_form = FormGroup({
UserRegistrationFieldKeys.nickName:
FormControl<String>(validators: [Validators.required]),
});
_form.control(_nickNameKey).value =
_getUserFieldFromLocalUseCase.invoke(_nickNameKey);
_form.markAsDirty();
}
void submitPressed(BuildContext context) {
_saveNickNameLocallyUseCase
.invoke(_form.control(_nickNameKey).value as String ?? '');
Navigator.pushNamed(context, Routes.LOGGED_OUT_EMAIL);
}
}
将 bloc 用于大多数与不可变状态更改相关的某些事情,并将我的 ViewModel 注入同一视图以处理表单验证并保持我的副作用执行功能是否有效?
为了完整起见,我将添加与 bloc 相关的代码,这样您就可以批评我是否得到了这个“bloc”的东西。请记住,此页面只有一个文本字段和一个按钮,而且我的表单中没有使用bloc,因此其他页面将从bloc 中获得比这个更多的好处:
集团:
import 'package:bloc/bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
part 'logged_out_nickname_state.dart';
part 'logged_out_nickname_cubit.freezed.dart';
class LoggedOutNicknameCubit extends Cubit<LoggedOutNicknameState> {
LoggedOutNicknameCubit() : super(const LoggedOutNicknameState.initialised());
void submitPressed() => emit(const LoggedOutNicknameState.submitted());
}
集团状态:
part of 'logged_out_nickname_cubit.dart';
@freezed
abstract class LoggedOutNicknameState with _$LoggedOutNicknameState {
const factory LoggedOutNicknameState.initialised() = _Initialised;
const factory LoggedOutNicknameState.submitted() = _Submitted;
}
我的看法:
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:get/get.dart';
import 'package:vepo/presentation/widgets/display/buttons/elevated_buttons/submit_button_widget.dart';
import 'package:vepo/presentation/widgets/display/containers/form_container_widget.dart';
import 'package:vepo/presentation/widgets/display/text/caption_widget.dart';
import 'package:vepo/presentation/widgets/display/text/subtitle_1_widget.dart';
import 'package:vepo/presentation/widgets/forms/text_field/text_field_widget.dart';
import 'package:vepo/presentation/widgets/pages/form_page_scaffold_widget.dart';
import 'package:vepo/presentation/widgets/pages/logo_header_widget.dart';
import 'cubit/logged_out_nickname_cubit.dart';
import 'logged_out_nick_name_controller.dart';
import 'logged_out_nick_name_cubit.dart';
class LoggedOutNickNameView extends GetView<LoggedOutNickNameController> {
@override
Widget build(BuildContext context) {
print('building loggedOUtNickName page');
final loggedOutNickNameViewModel =
BlocProvider.of<LoggedOutNickNameViewModel>(context);
final loggedOutNicknameCubit =
BlocProvider.of<LoggedOutNicknameCubit>(context);
return VpFormPageScaffold([
const VpLogoHeader(),
BlocConsumer<LoggedOutNickNameCubit, LoggedOutNickNameState>(
builder: (context, state) {
return state.when(
initialised: () =>
buildContent(loggedOutNickNameViewModel, loggedOutNicknameCubit),
submitted: () =>
buildContent(loggedOutNickNameViewModel, loggedOutNicknameCubit),
);
}, listener: (context, state) {
state.maybeWhen(
submitted: () => loggedOutNickNameViewModel.submitPressed(context),
orElse: () {});
}),
]);
}
Widget buildContent(LoggedOutNickNameViewModel loggedOutNickNameViewModel,
LoggedOutNicknameCubit loggedOutNicknameCubit) {
return VpFormContainer([
Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: const [
VpSubtitle1('So nice to meet you! What do your friends call you?',
TextAlign.center),
VpCaption('You can change this any time in settings...',
TextAlign.center),
]),
VpTextField(
loggedOutNickNameViewModel.nickNameKey,
'Nickname...',
validationMessages: (control) =>
{'required': 'Please enter your name / alter ego'},
textAlign: TextAlign.center,
maxLength: 20,
),
Center(
child:
VpSubmitButton('CONTINUE', loggedOutNicknameCubit.submitPressed))
], loggedOutNickNameViewModel.form);
}
}
【问题讨论】:
-
我已将 ViewModel 添加到 bloc 状态,这可能更惯用也可能不会更惯用。
标签: flutter bloc flutter-bloc