gpt4 book ai didi

flutter - 在不可变状态不实用的情况下的 Bloc 模式

转载 作者:行者123 更新时间:2023-12-04 15:12:07 25 4
gpt4 key购买 nike

我真的很难用 flutter_bloc 将我的 MVVM 模式转换为块模式对于一个非常简单的页面。我最关心的问题是我应该把执行副作用的函数放在哪里?
我有这个 BlocListener要在从 bloc 发出状态时执行副作用,并调用 ViewModel 来执行该副作用:

  BlocListener<LoggedOutNicknameCubit, LoggedOutNicknameState>(
listener: (context, state) {
state.maybeWhen(
submitted: () => loggedOutNickNameViewModel.submitPressed(context),
orElse: () {});
})
仅将 ViewModel 注入(inject) View 是否可以,该 View 包含执行副作用的函数,这样我就不必直接在 View 中执行副作用,因此我可以将业务逻辑与 View 分开?我是否还可以向该 ViewModel 添加可变状态,该状态对于不可变根本没有意义,因此处于从集团发出的“集团”状态没有意义?
我不得不说我确实想将 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 注入(inject)同一 View 以处理表单验证并保持我的副作用执行功能是否有效?
为了完整起见,我将添加我的 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 状态)。
考虑 ViewModel 中的字段应该去哪里,看起来有点像在发出状态后在 BlocBuilder 中使用的字段应该属于该状态。其他东西可以放在你认为合适的任何地方,所以我将它添加到肘部,因为它不是模式的真正一部分,而只是我的 View 消耗的辅助 Material 。
所以这是我目前从 MVVM 到 bloc 的这个页面的转换。随着我对集团模式的理解的增长,我会更新:
状态:

part of 'logged_out_nickname_cubit.dart';

@freezed
abstract class LoggedOutNickNameState with _$LoggedOutNickNameState {
factory LoggedOutNickNameState.initialised(
{String nickNameKey, FormGroup form}) = _Initialised;
factory LoggedOutNickNameState.submitted(
{String nickNameKey, FormGroup form}) = _Submitted;
}
肘:
part 'logged_out_nickname_state.dart';
part 'logged_out_nickname_cubit.freezed.dart';

class LoggedOutNickNameCubit extends Cubit<LoggedOutNickNameState> {
LoggedOutNickNameCubit(this.nickNameKey, this.form,
this.getUserFieldFromLocalUseCase, this.saveNickNameLocallyUseCase)
: super(LoggedOutNickNameState.initialised(
nickNameKey: nickNameKey, form: form)) {
form.control(nickNameKey).value =
getUserFieldFromLocalUseCase.invoke(nickNameKey);

form.markAsDirty();
}

final String nickNameKey;
final FormGroup form;
final GetUserFieldFromLocalUseCase getUserFieldFromLocalUseCase;
final SaveNickNameLocallyUseCase saveNickNameLocallyUseCase;

// the cubit version of "mapEventToState"
void submitPressed() => emit(
LoggedOutNickNameState.submitted(nickNameKey: nickNameKey, form: form));

void initialise() => emit(
LoggedOutNickNameState.initialised(nickNameKey: nickNameKey, form: form));

// just random helper functions for the view to consume
void onSubmitPressed(BuildContext context) {
saveNickNameLocallyUseCase
.invoke(form.control(nickNameKey).value as String ?? '');

Navigator.pushNamed(context, Routes.LOGGED_OUT_EMAIL,
arguments: LoggedOutEmailPageArgs(
form.control(nickNameKey).value as String ?? ''))
.then((value) => initialise());
}

void onBackPressed() {
saveNickNameLocallyUseCase
.invoke(form.control(nickNameKey).value as String ?? '');
close();
}
}
风景:
import 'logged_out_nickname_cubit.dart';

class LoggedOutNickNamePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
print('building loggedOUtNickName page');

final loggedOutNicknameCubit =
BlocProvider.of<LoggedOutNickNameCubit>(context);

return VpFormPageScaffold([
VpLogoHeader(loggedOutNicknameCubit.onBackPressed),
BlocConsumer<LoggedOutNickNameCubit, LoggedOutNickNameState>(
builder: (context, state) {
return state.when(
initialised: (nickNameKey, form) =>
_buildContent(nickNameKey, form, loggedOutNicknameCubit),
submitted: (nickNameKey, form) =>
_buildContent(nickNameKey, form, loggedOutNicknameCubit),
);
}, listener: (context, state) {
state.maybeWhen(
submitted: (nickNameKey, form) =>
loggedOutNicknameCubit.onSubmitPressed(context),
orElse: () {});
}),
]);
}

Widget _buildContent(
String nickNameKey, FormGroup form, LoggedOutNickNameCubit cubit) {
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(
nickNameKey,
'Nickname...',
validationMessages: (control) =>
{'required': 'Please enter your name / alter ego'},
textAlign: TextAlign.center,
maxLength: 20,
),
Center(child: VpSubmitButton('CONTINUE', cubit.submitPressed))
], form);
}
}

关于flutter - 在不可变状态不实用的情况下的 Bloc 模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65032673/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com