Comment dispatcher les événements Bloc en dehors du Widget ?
Je suis nouveau dans l'architecture Bloc et j'ai regardé quelques tutoriels récemment. J'ai une page qui est StatelessWidget et à l'intérieur, j'utilise BlocProvider pour initialiser Bloc dans mon interface utilisateur. Il renverra différents widgets en fonction des changements d'état.
Mais même dans les didacticiels, ils n'ont envoyé des événements qu'à partir d'autres widgets (par exemple en appuyant sur le bouton). Mais dans ma situation, je dois appeler l'appel d'API init en dehors de Widget qui se trouve dans Bloc Event.
Si je suis dans un autre Widget, je peux appeler BlocProvider.of<FirstTabBloc>(context).dispatch(GetUserProfile());
mais je ne peux pas l'appeler dans main() car le contexte ne provient pas du Widget.
Code:
class FirstPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
child: firstTabElement(context),
),
appBar: EmptyAppBar(mainAppColor),
);
}
BlocProvider<FirstTabBloc> firstTabElement(BuildContext context) {
return BlocProvider(
builder: (_) => sl<FirstTabBloc>(),
child: Expanded(
child: Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: Column(
children: <Widget>[
Stack(
children: [
//Main Background
Column(children: <Widget>[
//Top part
Container(
constraints: BoxConstraints(
minHeight: 120,
),
width: MediaQuery.of(context).size.width,
height: 300,
decoration: new BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: ticketGradient,
),
),
),
// Bottom part - white
Container(
color: basicWhite,
),
]),
//content above background
BlocBuilder<FirstTabBloc, FirstTabState>(
builder: (context, state) {
if (state is Uninitialized) {
return WalletWidget(
credit: formatPrice(0),
currency: '€',
);
} else if (state is Loading) {
return LoadingWidget();
} else if (state is Loaded) {
Wallet currWallet = state.profile.getWalletByClient(clientId);
return WalletWidget(
credit: formatPrice(currWallet.value),
currency: formatCurrency(currWallet.currency),
);
} else if (state is Error) {
return MessageDisplay(
message: state.message,
);
}
},
),
],
),
],
),
)));
}
}
Réponses
Vous devez utiliser un autre moyen d'obtenir le bloc.
BlocProvider.of(context)
utilise Provider
sous le capot. Provider est un package Flutter, qui encapsule InheritedWidget
. InheritedWidget est un widget flutter qui transmet les données dans l'arborescence des widgets via le contexte.
Donc, vous avez besoin d'un autre moyen. Par exemple, vous pouvez utiliser la bibliothèque get_it . C'est l'implémentation de fléchettes de Service Locator
.
Exemple simple avec le bloc en dehors du widget
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
final bloc = CounterBloc();
void main() {
bloc.add(CounterEvent.increment);
bloc.add(CounterEvent.increment);
bloc.add(CounterEvent.increment);
bloc.add(CounterEvent.increment);
runApp(
MyApp(),
);
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
body: SafeArea(
child: MyHomePage(),
),
),
);
}
}
class MyHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (_) => bloc,
child: CounterPage(),
);
}
}
class CounterPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Counter')),
body: BlocBuilder<CounterBloc, int>(
builder: (_, count) {
return Center(
child: Text('$count', style: Theme.of(context).textTheme.headline1),
);
},
),
floatingActionButton: Column(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(vertical: 5.0),
child: FloatingActionButton(
child: const Icon(Icons.add),
onPressed: () =>
context.bloc<CounterBloc>().add(CounterEvent.increment),
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 5.0),
child: FloatingActionButton(
child: const Icon(Icons.remove),
onPressed: () =>
context.bloc<CounterBloc>().add(CounterEvent.decrement),
),
),
],
),
);
}
}
enum CounterEvent { increment, decrement }
class CounterBloc extends Bloc<CounterEvent, int> {
CounterBloc() : super(0);
@override
Stream<int> mapEventToState(CounterEvent event) async* {
switch (event) {
case CounterEvent.decrement:
yield state - 1;
break;
case CounterEvent.increment:
yield state + 1;
break;
default:
addError(Exception('unsupported event'));
}
}
}
Enregistrez votre bloc dans get_it. Et après cela, vous pouvez l'obtenir et l'utiliser sans le contexte.