当前位置:网站首页>Use bloc to build a page instance of shutter
Use bloc to build a page instance of shutter
2022-07-03 12:23:00 【Ma Nong @ official account on the island with the same name】
Preface
We talked about... In our last article BlocProvider
Use , Sense and Provider
It's almost the same , Nothing new . In the last article, there was a BlocBuilder It's a little strange , Let's review the code :
BlocBuilder<CounterCubit, int>(
builder: (context, count) => Text(
'$count',
style: TextStyle(
fontSize: 32,
color: Colors.blue,
),
),
Inside count
Will automatically follow BlocProvider
The state of the object changes , But we don't see the binding action , For example, we use Provider
It's using context.watch
Method , But there is no . What's the matter with this ? In this article, we will introduce BlocBuilder
Use .
BlocBuilder Binding to state objects
flutter_bloc In the source BlocBuilder Is defined as follows :
class BlocBuilder<B extends BlocBase<S>, S> extends BlocBuilderBase<B, S> {
const BlocBuilder({
Key? key,
required this.builder,
B? bloc,
BlocBuilderCondition<S>? buildWhen,
}) : super(key: key, bloc: bloc, buildWhen: buildWhen);
final BlocWidgetBuilder<S> builder;
@override
Widget build(BuildContext context, S state) => builder(context, state);
}
There are two ways to bind state objects , Not specified in bloc
Parameter time , It will pass. BlocProvider
and context
Automatically look up for matching status objects . This code is in its parent class BlocBuilderBase
( It's a StatefulWidget
) Of State
Object , In fact, it's still context.read
To complete .
@override
void initState() {
super.initState();
_bloc = widget.bloc ?? context.read<B>();
_state = _bloc.state;
}
And if you specify bloc
Parameters , Then use the specified bloc
object , In this way, you can use your own bloc
Object without BlocProvider
Provide . This usage is a bit like GetX Of GetBuilder
了 . For example, our counter application , It can be simplified to the following form .
class BlocBuilderDemoPage extends StatelessWidget {
final counterCubit = CounterCubit();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Bloc Counter '),
),
body: Center(
child: BlocBuilder<CounterCubit, int>(
builder: (context, count) => Text(
'$count',
style: TextStyle(
fontSize: 32,
color: Colors.blue,
),
),
bloc: counterCubit,
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
counterCubit.increment();
},
tooltip: ' Click to increase ',
child: Icon(Icons.add),
),
);
}
}
Refresh by conditions
BlocBuilder
One more parameter buildWhen
, This is a return bool
Callback method of value :
typedef BlocBuilderCondition<S> = bool Function(S previous, S current);
That is, we can decide whether to refresh the interface according to the front and back States . for instance , For example, the data before and after refresh is consistent , Then there's no need to refresh the interface . Let's verify it with the imitation Nuggets personal home page written before . In order to complete the network request service , We constructed four states :
enum LoadingStatus {
loading, // load
success, // Loading successful
failed, // Loading failed
}
And then use Bloc
Of event
Pattern , Definition 3 individual Event
.
abstract class PersonalEvent {}
// Get data events
class FetchEvent extends PersonalEvent {}
// Success Events
class FetchSucessEvent extends PersonalEvent {}
// Failure events
class FetchFailedEvent extends PersonalEvent {}
At the same time, a response state data class is defined , Aggregating personal information objects and loading states .
class PersonalResponse {
PersonalEntity? personalProfile;
LoadingStatus status = LoadingStatus.loading;
PersonalResponse({this.personalProfile, required this.status});
}
PersonalBloc
The code implementation is as follows , Corresponding 3 The way we handle these events is as follows :
FetchEvent
: Request network data ;FetchSucessEvent
: After loading successfully , Build a new... With the requested personal information object and loading statusPersonalResponse
object , Useemit
The notification interface is refreshed ;FetchFailedEvent
: Loading failed , emptyPersonalResponse
Personal information object , And mark the loading status as failed .
class PersonalBloc extends Bloc<PersonalEvent, PersonalResponse> {
final String userId;
PersonalEntity? _personalProfile;
PersonalBloc(PersonalResponse initial, {required this.userId})
: super(initial) {
on<FetchEvent>((event, emit) {
getPersonalProfile(userId);
});
on<FetchSucessEvent>((event, emit) {
emit(PersonalResponse(
personalProfile: _personalProfile,
status: LoadingStatus.success,
));
});
on<FetchFailedEvent>((event, emit) {
emit(PersonalResponse(
personalProfile: null,
status: LoadingStatus.failed,
));
});
on<RefreshEvent>((event, emit) {
getPersonalProfile(userId);
});
add(FetchEvent());
}
void getPersonalProfile(String userId) async {
_personalProfile = await JuejinService().getPersonalProfile(userId);
if (_personalProfile != null) {
add(FetchSucessEvent());
} else {
add(FetchFailedEvent());
}
}
}
In the constructor, we directly request data ( You can also let the interface control ). The implementation of the page is the same as before GetX
Similar ( See :Flutter Introduction and actual combat ( 73 ): Then follow the personal homepage of nuggets GetX and Provider Between PK), It's just that we use BlocBuilder
To complete . The code is as follows :
class PersonalHomePage extends StatelessWidget {
PersonalHomePage({Key? key}) : super(key: key);
final personalBloc = PersonalBloc(
PersonalResponse(
personalProfile: null,
status: LoadingStatus.loading,
),
userId: '70787819648695');
@override
Widget build(BuildContext context) {
return BlocBuilder<PersonalBloc, PersonalResponse>(
bloc: personalBloc,
builder: (_, personalResponse) {
print('build PersonalHomePage');
if (personalResponse.status == LoadingStatus.loading) {
return Center(
child: Text(' Loading ...'),
);
}
if (personalResponse.status == LoadingStatus.failed) {
return Center(
child: Text(' request was aborted '),
);
}
PersonalEntity personalProfile = personalResponse.personalProfile!;
return Stack(
children: [
CustomScrollView(
slivers: [
_getBannerWithAvatar(context, personalProfile),
_getPersonalProfile(personalProfile),
_getPersonalStatistic(personalProfile),
],
),
Positioned(
top: 40,
right: 10,
child: IconButton(
onPressed: () {
personalBloc.add(FetchEvent());
},
icon: Icon(
Icons.refresh,
color: Colors.white,
),
),
),
],
);
},
buildWhen: (previous, next) {
if (previous.personalProfile == null || next.personalProfile == null) {
return true;
}
return previous.personalProfile!.userId != next.personalProfile!.userId;
},
);
}
// Other codes are omitted
}
Here we add a refresh button , Each click will launch a FetchEvent
To request new data , And in BlocBuilder
Of builder
Use in print
Print interface refresh information . But we built a buildWhen
Parameters , Only the current last two users id Refresh the interface only when it is inconsistent ( In fact, you can also compare objects , Overload required PersonalEntity
Of ==
and hashCode
Method ), To reduce unnecessary interface refresh . Then we comment out this line of code , Then go straight back true, That is, refresh every time . Let's look at the comparison of the two effects .

You can see , After judging the service conditions , Clicking the refresh button will not refresh the interface , This is because we use userId
It's all the same . And if you comment it out, you will directly return true
after , Every time you click the refresh button, it will refresh . In this way , We can reduce unnecessary interface refresh when the user refreshes but the data does not change . Please download the complete source code here :BLoC State management source code .
summary
As can be seen from this article ,BlocBuilder
The use of is quite simple , and Bloc
Of event
The model is actually in harmony with Redux
The pattern of ( You can refer to :Flutter Introduction and actual combat ( fifty-nine ): Hand in hand with you Redux The middleware implements asynchronous state management ) It's quite similar , Are triggered by user behavior , And then respond to the event , Return a new data object in status management to trigger interface refresh . and BlocBuilder
Both can cooperate BlocProvider
Use... In the component tree Bloc
object , You can also have your own Bloc
object . While using buildWhen
Callback function , You can decide whether to refresh the interface by comparing the status data before and after , So as to reduce unnecessary interface refresh .
边栏推荐
猜你喜欢
CGroup introduction
云计算未来 — 云原生
laravel 时区问题timezone
Laravel time zone timezone
Shutter widget: centerslice attribute
Display time with message interval of more than 1 minute in wechat applet discussion area
Php Export word method (One MHT)
OpenGL draws colored triangles
(构造笔记)ADT与OOP
Wechat applet pages always report errors when sending values to the background. It turned out to be this pit!
随机推荐
Dart: self study system
Dart: about grpc (I)
Computer version wechat applet full screen display method, mobile phone horizontal screen method.
实现验证码验证
云计算未来 — 云原生
Integer int compare size
Flutter Widget : KeyedSubtree
PHP導出word方法(一mht)
2.9 overview of databinding knowledge points
Wrong arrangement (lottery, email)
New features of ES6
Capturing and sorting out external Fiddler -- Conversation bar and filter [2]
DEJA_ Vu3d - cesium feature set 053 underground mode effect
Unicode查询的官方网站
Prompt unread messages and quantity before opening chat group
Simple factory and factory method mode
Solutions to the failure of installing electron
Atomic atomic operation
Adult adult adult
Talk about the state management mechanism in Flink framework