Flutter_bloc 框架使用笔记,后续估计都不太会用了 (1)
final String phone;
@overrideWidget build(BuildContext context) {return BlocListener<RegisterBloc, RegisterState>(listener: (ctx, state) {if (state.status.isSubmissionInProgress) {EasyLoading.show(maskType: EasyLoadingMaskType.clear, dismissOnTap: false);return;}if (state.status.isSubmissionFailure) {EasyLoading.dismiss();var message = LS.of(context, "register_error");EasyLoading.showError('{state.errMessage ?? ''}');return;}if (state.status.isSubmissionSuccess) {EasyLoading.dismiss();showCupertinoDialog(context: context,builder: (context) {returnAlertDialog(content: Text(LS.of(context, "register_success")),actions: [TextButton(onPressed: (){Navigator.of(context).popUntil(ModalRoute.withName("/"));}, child: Text(LS.of(context, "confirm")))],);});}},child: Align(alignment: Alignment(0, -1),child: Padding(padding: const EdgeInsets.only(top: 31, left: 36, right:36),child: Column(children: [_UsernameIn
put(),_PasswordInput(),_ConfirmPasswordInput(),const SizedBox(height: 20,),_RegisterButton()]),),));}}
class _RegisterButton extends StatelessWidget {@overrideWidget build(BuildContext context) {return BlocBuilder<RegisterBloc, RegisterState>(builder: (context, state) {return CircleRectButton(child: Text(LS.of(context, "register"), style: TextStyle(letterSpacing: 20)),onPressed: state.status.isValidated? () async {context.read<RegisterBloc>().add(RegisterSubmitEvent());}: null);});}}
BlocListener: 通过BlocListener来监听状态消息,收到消息 child 不会 rebuild。适合拿来弹出加载页,错误信息等。
BlocBuilder 通过BlocBuilder来包装需要修改的内容。 这里的在组装页面的时候尽量在涉及到更新的地方使用 BlocBuilder,也尽可能的考虑buildwhen 属性。保持当必须要更新时才重新 build 的思路。
- bloc 
bloc 在封装后没什么逻辑,他的思路就是接受页面的事件,转为状态变更返回给页面。
class RegisterBloc extends Bloc<RegisterEvent, RegisterState> {
RegisterBloc(RegisterState initialState) : super(initialState);
@overrideStream<RegisterState> mapEventToState(RegisterEvent event,) async* {try {yield* event.applyAsync(currentState: state, bloc: this);} catch (, stackTrace) {developer.log('$', name: 'RegisterBloc', error: _, stackTrace: stackTrace);yield state;}}}
将对应的事件处理放在 event 里面去执行显然更符合设计模式。代码也会更清晰,而不用做很多判断
if(event is event){do()} else if (event is event) {do()}
- event 
@immutableabstract class RegisterEvent {const RegisterEvent();Stream<RegisterState> applyAsync({required RegisterState currentState, required RegisterBloc bloc});}
class UsernameChangeEvent extends RegisterEvent {const UsernameChangeEvent(this.username);final String username;
Stream<RegisterState> applyAsync({required RegisterState currentState, required RegisterBloc bloc}) async* {var input = UsernameInput.dirty(username);var status = Formz.validate([input, currentState.password, currentState.confirmPassword]);yield currentState.copyWith(username: input, status: status);}
}
抽象 event,定义事件接口。 子类 event 来接收参数,实现事件接口并抛出新的状态给页面。
- state 
class RegisterState extends Equatable {final UsernameInput username;final PasswordTwoInput password;final PasswordTwoInput confirmPassword;final FormzStatus status;final String? errMessage;RegisterState({this.username = const UsernameInput.pure(),this.password = const PasswordTwoInput.pure(),this.confirmPassword = const PasswordTwoInput.pure(),this.status = FormzStatus.pure,this.errMessage});
@overrideList<Object> get props => [username, password, confirmPassword, status];
RegisterState copyWith({UsernameInput? username,PasswordTwoInput? password,PasswordTwoInput? confirmPassword,FormzStatus? status,}) {return RegisterState(username: username ?? this.username,password: password ?? this.password,confirmPassword: confirmPassword ?? this.confirmPassword,status: status ?? this.status,);}}
state 可以考虑抽象 state 和单独一个 state 类。看具体业务吧。如果属性很简单,可以考虑抽象。属性比较多的情况下就没必要抽象了。
思路总结
- Page 作为整个页面的对外对象,给外部调用,同时定义和注册了本页面需要用的 bloc. 
- Screen 配置了整个页面展示的 widget。并把事件抛给 bloc.通过接收 bloc 的最新状态,并 rebuild UI. 
- bloc 里面处理事件并转为 state 返回给页面题外话 
Cubit
还有一套 cubit 的简单模板,其实就是把 bloc 换成了 cubit。去掉了 event 的逻辑。screen 里面事件调用 cubit 的方法。在 cubit 里面 emit(new state).如此页面就可以接收到最新的状态了。
GET
在使用体验上 GET 框架不依赖 context。对于使用体验来说应该更好些。对于简单的状态管理,也是 GET 更方便。











 
    
评论