我知道 flutter 中的 BLoC 就像 android 的 MVVM 中的 viewmodel 层,因此在配置更改时不会一次又一次地获取数据(例如:屏幕方向的更改)。
我很困惑提供者是替换 BLoC 模式中 RxDart 的功能还是替换角色 BLoC 模式本身。
此外,如果我根本不使用 BLoC,那么应用程序是否会在配置更改后继续存在。
请通过一些用例解释提供程序对 BLoC、RxDart 组合的限制。
目前我正在 Flutter 中使用 BLoC,我有一个关于 Bloc 中多个流的问题。
例如,当一个屏幕有多个应该依赖于 Bloc 的小部件时。我可以将整个屏幕包裹在 StreamBuilder 中,但是每次都会重建所有小部件。
示例块:
class TestBloc {
final StreamController _dataController = StreamController<String>();
final StreamController _appBarTitleController = StreamController<String>();
TestBloc();
Stream<String> get appBarTitle => _appBarTitleController.stream;
Stream<DataState> get data => _dataController.stream;
void fetchData(String path) async {
_dataController.sink.add(PokemonDataLoading());
Data data = await _getData();
_dataController.sink.add(Loaded(data));
_appBarTitleController.sink.add(data.name);
}
Future<Data> _getData(String path) async {
return await _dataRepository.fetchData(path);
}
void dispose() {
_dataController.close();
_appBarTitleController.close();
}
}
Run Code Online (Sandbox Code Playgroud)
在示例构建方法中,您可以看到两种不同的 StreamBuilder,一种用于应用栏标题,一种用于内容。当然,我可以在本示例中将它们包装到一个 StreamBuilder 中,但有时这并不容易。它们可能取决于其他数据或用户交互。
@override
Widget build(BuildContext context) {
_testBloc.fetchData();
return ScaffoldWithSafeArea(
title: StreamBuilder( …Run Code Online (Sandbox Code Playgroud) 我正在尝试使用 bloc 模式创建带有 API 数据的列表视图,错误如下:
'package:flutter/src/widgets/framework.dart':断言失败:第 5120 行 pos 12:'child == _child':不正确。
我的列表文件:
import 'package:Instant_Feedback/Dashboard/PeopleList/bloc/bloc.dart';
import 'package:Instant_Feedback/People/strongConnection_model.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class PeopleListing extends StatefulWidget {
@override
State<StatefulWidget> createState() => _PeopleListingState();
}
class _PeopleListingState extends State<PeopleListing> {
PeopleListBloc peopleBloc;
@override
void initState() {
super.initState();
peopleBloc = BlocProvider.of<PeopleListBloc>(context);
peopleBloc.dispatch(DisplayPeopleList());
}
@override
Widget build(BuildContext context) {
return BlocBuilder(
bloc: peopleBloc,
builder: (context, state){
if (state is PeopleUninitializedState) {
print("PeopleUninitializedState");
} else if (state is PeopleFetchingState) {
print("PeopleFetchingState");
} else if (state is …Run Code Online (Sandbox Code Playgroud) 我对状态管理的理解是,setState()单独调用会带来各种混乱的问题,代码文件变得庞大且难以调试,并且它阻止了项目的合理结构。在小部件的外观略有变化的情况下,拥有像 BLoC 或 ScopedModel 这样的复杂架构只是为了显示/隐藏小部件(例如)是没有意义的。然而,我所理解的方式是你不能将setState()一个架构混合在一起,否则架构的意义何在?
让我们对这个问题使用 BLoC(只是因为我碰巧在使用它),特别是这个 package。假设我有这个超级简单的示例代码:
class MyWidget extends StatefulWidget {
@override
void createState() {
return _MyWidgetState();
}
}
class _MyWidgetState extends State<MyWidget>() {
bool _isShowing = false;
MyBloc bloc;
@override
void initState() {
super.init();
bloc = MyBloc();
}
@override
Widget build(BuildContext context) {
return BlocBuilder(
bloc: bloc,
builder: (context, state) {
return Column(
children: <Widget>[
Text(state.myText),
if (_isShowing)
Text("Button has been pressed!"),
RaisedButton(
child: Text("Show label"),
onTap: () => setState(() => …Run Code Online (Sandbox Code Playgroud) 我使用 Flutter 工作了很长时间,并发布了很多产品。我从来没有真正喜欢过 BLoC,更喜欢使用 Provider 或后来的 Riverpod。
我只是不明白该事件的概念。为什么我们还需要它?我很困惑,因为它的实际受欢迎程度...... BLoC 有 Cubit 子类,似乎使用起来更简单,但每个人都只是不停地说:“Cubit 更简单,但功能不那么强”。但有什么限制呢?
我什至认为肘尺更有用,同时也更简单:
示例:用户点击某些产品的“添加到购物车”按钮。
肘:
cartCubit.addProduct(productId);
Run Code Online (Sandbox Code Playgroud)
集团:
cartBloc.addEvent(UserAddsProductEvent(productId));
Run Code Online (Sandbox Code Playgroud)
在它们里面:
肘:
void addProduct(String productId) async {
//some validation...
if(...){...}
final result = await cartRepo.addProduct(id);
if(result == ...) {
state = someState;
//....
}
Run Code Online (Sandbox Code Playgroud)
集团:
void addEvent(CartEvent event) {
if (event is UserAddsProductEvent) {
_addProduct(event.productId)
} else if (event is....) {
//.....
}
}
void _addProduct(String productId) async {
//some validation...
if(...){...}
final result = …Run Code Online (Sandbox Code Playgroud) 假设我们使用以下代码导航到“PageA”:
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return BlocProvider(
create: (context) => BlocA(),
child: PageA(),
);
},
),
);
Run Code Online (Sandbox Code Playgroud)
当“PageA”导航到“PageB”时。我如何访问“BLocA”?我尝试使用以下代码从“PageA”导航到“PageB”,但它崩溃了。
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return BlocProvider(
create: (context) => contxt.read<BlocA>(),
child: PageB(),
);
},
),
);
Run Code Online (Sandbox Code Playgroud) 我正在关注到新块 8.0.0 的迁移。我正在尝试删除 mapEventToState但 我在这样做时遇到困难。你能帮我看看该怎么做吗?我已经在下面尝试过,但它不起作用。
旧代码:
class SignInBloc extends Bloc<SignInEvent, SignInState> {
final AuthenticationRepository authenticationRepository;
final UserDataRepository userDataRepository;
SignInBloc(
{required this.authenticationRepository,
required this.userDataRepository})
: super(SignInInitialState());
SignInState get initialState => SignInInitialState();
@override
Stream<SignInState> mapEventToState(
SignInEvent event,
) async* {
if (event is SignInWithGoogle) {
yield* mapSignInWithGoogleToState();
}
}
Stream<SignInState> mapSignInWithGoogleToState() async* {
yield SignInWithGoogleInProgressState();
try {
String res = await authenticationRepository.signInWithGoogle();
yield SignInWithGoogleCompletedState(res);
} catch (e) {
print(e);
yield SignInWithGoogleFailedState();
}
}
...
Run Code Online (Sandbox Code Playgroud)
迁移代码(不起作用):
class SignInBloc extends Bloc<SignInEvent, …Run Code Online (Sandbox Code Playgroud) 我正在构建一个登录页面,并且已经创建了打算用作完全动态 TextField 小部件的内容。
我现在需要创建该小部件的 2 个实例(电子邮件和密码输入)并发送hintText、errorText 的参数,然后发送我的LoginBloc 和验证方法,这些参数对于每个输入当然是不同的。
我的问题是 Dart 不允许我使用小部件接收的块作为类型,因此代码不起作用。
我可以做什么来解决这个问题?或者我完全做错了,有更好的方法吗?
登录页面:
@override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: Padding(
padding: const EdgeInsets.only(
left: 16,
right: 16,
),
child: SingleChildScrollView(
child: Column(
children: <Widget>[
Container(
margin: EdgeInsets.only(top: 50),
child: Text(
AppLocalizations.of(context).initiateSession,
style: Theme.of(context).textTheme.headline6,
),
),
BlocProvider(
create: (context) {
return LoginBloc();
},
child: BlocListener<LoginBloc, LoginState>(
listener: (context, state) {
if (state.status.isSubmissionFailure) {
ScaffoldMessenger.of(context)
..hideCurrentSnackBar()
..showSnackBar(
const SnackBar(
content: Text('Authentication Failure')),
);
}
},
child: Align(
alignment: …Run Code Online (Sandbox Code Playgroud) 我有一个带有三个小部件 [widgetA、widgetB、widgetC] 的屏幕,我有一个 bloc[BlocA] 负责数据获取并在该屏幕上显示我有三个事件 [eventA、eventB、eventC] 渲染小部件 [ widgetA、widgetB、widgetC] 和我有三个状态 [stateA、stateB、stateC],它们负责管理小部件的状态 [widgetA、widgetB、widgetC] 我已附加所有代码来重现和测试该案例。
我一次只能显示一种状态及其各自的小部件,而我想根据它们的事件显示所有三种状态及其小部件。任何帮助将不胜感激。
我尝试实现相同目标的唯一方法是为每个小部件创建单独的块和事件类,但不知何故我对这种方法不满意。
实现这个用例的最佳方法是什么?
测试屏幕
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:locus/blocs/test/testbloc.dart';
class TestScreen extends StatelessWidget {
const TestScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => TestBloc()..add(const TestEvent1()),
child: Scaffold(
appBar: AppBar(
title: const Text('Test'),
),
body: Stack(
children: [
Builder(builder: (context) {
return Padding(
padding: const EdgeInsets.only(top: 0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () =>
context.read<TestBloc>().add(const TestEvent1()),
child: const Text("Event1")), …Run Code Online (Sandbox Code Playgroud) 我正在使用flutter_bloc包。如果我有一个状态是小部件列表的块,这是一个不好的做法吗?我使用这个块从列表中推送(添加)和弹出(删除)小部件/迷你屏幕。我将此列表用作弹出菜单的主体,其中有类似嵌入式导航的内容。列表的最后一个成员是显示在弹出窗口中的小部件。
每次我按下或弹出时,我都会发出一个新的状态。该块很有用,因为这样我就可以从弹出窗口中显示的小部件/迷你屏幕中的任何位置调用推送或弹出。如果我的用例很清楚或者您需要更多详细信息,请告诉我。谢谢。
以下是相关代码片段:
自定义堆栈(其中E类型为Widget):
class PopoverStack<E> {
PopoverStack() : _storage = <E>[];
final List<E> _storage;
void push(E element) {
_storage.add(element);
}
void pop() {
_storage.removeLast();
}
E get last => _storage.last;
bool get isEmpty => _storage.isEmpty;
bool get isNotEmpty => !isEmpty;
PopoverStack.of(PopoverStack<E> stack) : _storage = List<E>.of(stack._storage);
}
Run Code Online (Sandbox Code Playgroud)
Bloc for stack(PopoverPage是一个抽象类小部件将扩展):
class PopoverCardStackBloc extends Cubit<PopoverStack<PopoverPage>> {
PopoverCardStackBloc(PopoverStack<PopoverPage> popoverStack) : super(popoverStack);
void push(PopoverPage element) {
emit(PopoverStack.of(state..push(element)));
}
void pop() {
emit(PopoverStack.of(state..pop()));
}
} …Run Code Online (Sandbox Code Playgroud)