如何在 Widget 之外调度 Bloc 事件?
Posted
技术标签:
【中文标题】如何在 Widget 之外调度 Bloc 事件?【英文标题】:How to dispatch Bloc events outside of Widget? 【发布时间】:2020-12-07 09:10:15 【问题描述】:我是 Bloc 架构的新手,最近看了一些教程。我有一个 StatelessWidget 页面,在里面我使用 BlocProvider 在我的 UI 中初始化 Bloc。它将根据状态变化返回不同的小部件。
但即使在教程中,它们也仅从其他小部件(例如通过按下按钮)分派事件。但在我的情况下,我需要在 Bloc Event 中的 Widget 之外调用 init API。
如果我在其他 Widget 中,我可以调用 BlocProvider.of<FirstTabBloc>(context).dispatch(GetUserProfile());
,但我不能在 main() 中调用它,因为上下文不是来自 Widget。
代码:
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,
);
,
),
],
),
],
),
)));
【问题讨论】:
为什么在 main 中需要它? 我想在启动时调用 API,结果会改变状态/在屏幕上绘制不同的小部件。 在 main 中这样做可能不是一个好主意。您应该使用某种闪屏或用户交互的东西。不建议在 main 中进行繁重的工作。 【参考方案1】:你需要用另一种方式来获得集团。
BlocProvider.of(context)
在后台使用Provider
。 Provider 是一个颤振包,它包裹了 InheritedWidget
。 InheritedWidget 是 Flutter 小部件,它通过上下文将数据向下传递到小部件树。
所以你需要另一种方式。例如,您可以使用 get_it 库。这是Service Locator
的飞镖实现。
小部件外部块的简单示例
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'));
在 get_it 中注册您的集团。之后,您可以在没有上下文的情况下获取并使用它。
【讨论】:
我正在使用它'sl我想你需要知道 dispatch renamed to add
> There were core api changes introduced into 1.0.0:
bloc.state.listen -> bloc.listen
bloc.currentState -> bloc.state
bloc.dispatch -> bloc.add
bloc.dispose -> bloc.close
查看https://link.medium.com/qnfMcEcW00 了解更多详情。 希望对你有帮助?
【讨论】:
以上是关于如何在 Widget 之外调度 Bloc 事件?的主要内容,如果未能解决你的问题,请参考以下文章
Flutter Bloc 如何从 Widget 本身更新 BlocBuilder 中的 Widget?
调度第一个 bloc 事件或 cubit 方法,在 StatelessWidget 内的页面开始