위젯 외부에서 Bloc 이벤트를 전달하는 방법은 무엇입니까?
저는 Bloc 아키텍처를 처음 접했고 최근에 튜토리얼을 봤습니다. StatelessWidget 페이지가 있고 내부 UI에서 Bloc을 초기화하기 위해 BlocProvider를 사용하고 있습니다. 상태 변경에 따라 다른 위젯을 반환합니다.
그러나 튜토리얼에서도 그들은 다른 위젯에서만 이벤트를 전달했습니다 (예 : 버튼을 누름). 하지만 제 상황에서는 Bloc Event에있는 Widget 외부에서 init API 호출을 호출해야합니다.
다른 위젯 내부에 있으면 호출 할 수 BlocProvider.of<FirstTabBloc>(context).dispatch(GetUserProfile());
있지만 컨텍스트가 위젯에서 가져 오지 않기 때문에 main ()에서 호출 할 수 없습니다.
암호:
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,
);
}
},
),
],
),
],
),
)));
}
}
답변
블록을 얻으려면 다른 방법을 사용해야합니다.
BlocProvider.of(context)
Provider
후드 아래에서 사용 합니다. Provider 는을 래핑하는 flutter 패키지입니다 InheritedWidget
. InheritedWidget 은 컨텍스트를 통해 위젯 트리 아래로 데이터를 전달하는 flutter 위젯입니다.
따라서 다른 방법이 필요합니다. 예를 들어 get_it 라이브러리를 사용할 수 있습니다 . .NET의 다트 구현입니다 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에 블록을 등록하십시오. 그리고 그 후에는 그것을 얻고 문맥없이 사용할 수 있습니다.