尝试学习 BLoCs 我想出了这个问题。我有一些代码,我在其中生成了一些带有 BLoC 模式的按钮。但是,我不知道如何使用dispatch(event)方法更新特定的按钮属性。如何将参数传递给事件ChangeSomeValues?
使用 BLoC 的部分
BlocBuilder(
bloc: myBloc,
builder: (context, state) {
return ListView.builder(
itemCount: state.buttonList.length,
itemBuilder: (context, index) {
return MyButton(
label: buttonList[index].label,
value: buttonList[index].value,
onPressed: myBloc.dispatch(ChangeSomeValues()),
);
}
);
}
),
Run Code Online (Sandbox Code Playgroud)
MyBloc.dart
class MyBloc extends Bloc<MyEvent, MyState> {
@override
Stream<MyState> mapEventToState(MyEvent event) async* {
if (event is ChangeSomeValues) {
... modify specific parameters in list here ...
yield MyState1(modifiedList);
}
}
}
Run Code Online (Sandbox Code Playgroud)
我知道如何使用事件来更改值,但我找不到如何使用这种通用实现来编辑列表中的特定参数。
我正在开发 Flutter 应用程序,我注意到每当我保存我的应用程序以查看更新的更改时,我的整个应用程序都会重新加载。我希望我打开的页面可以热加载我的新更改。
我认为我的小部件树的组织方式可能会对此产生影响。我的整个应用程序都包含在一个在启动时运行的小部件中,该小部件会初始化为 ServicesLoadingState。然后,在服务完成启动后(在 BLoC 中),它产生一个 ServicesReadyState,然后绘制我的所有小部件。我认为当我热重载时,最上面的小部件的状态会切换回 ServicesLoadingState,重新加载服务,并向我展示我正在经历的行为。
我试过谷歌搜索“flutter hot reload restarts app”,但我没有找到任何关于如何防止这种情况的好提示。如何阻止热重载重新启动整个应用程序?
在下面显示的代码中,在获取 BuildContext 对象后从 build 方法中调用 dispatch 事件。如果我希望做的是在 initState 方法本身内的页面开始处理期间分派事件怎么办?
如果我使用 didChangeDependencies 方法,那么我会收到这个错误:
BlocProvider.of() called with a context that does not contain a Bloc of type FileManagerBloc.如何解决这个问题?
@override
Widget build(BuildContext context) {
return Scaffold(
body: BlocProvider<FileManagerBloc>(
builder: (context)=>FileManagerBloc(),
child: SafeArea(
child: Container(
child: Column(
children: <Widget>[
Container(color: Colors.blueGrey, child: TopMenuBar()),
Expanded(
child: BlocBuilder<FileManagerBloc,FileManagerState>(
builder: (context , state){
return GridView.count(
scrollDirection: Axis.vertical,
physics: ScrollPhysics(),
crossAxisCount: 3,
crossAxisSpacing: 10,
children: getFilesListWidget(context , state),
);
},
),
)
],
),
),
),
)); …Run Code Online (Sandbox Code Playgroud) 我有一个 Bloc 类,需要基于同一流控制器的三个流。
class TodoBloc {
final _todoController = StreamController<List<TodoModel>>();
get allTodoStream => _todoController.stream;
get activeTodoStream => _todoController.stream
.map<List<TodoModel>>(
(list) => list.where((item) => item.state == 0));
get completedTodoStream => _todoController.stream
.map<List<TodoModel>>(
(list) => list.where((item) => item.state == 1));}
Run Code Online (Sandbox Code Playgroud)
这是一个有状态的待办事项列表。我想在与检索其他状态的流分开的流中检索具有活动状态的待办事项。
我有一个方法负责过滤并根据过滤器值返回一个流。这是方法:
Stream<List<TodoModel>> filterTodoLs(String filter) {
if (filter == 'all') {
return todoStream;
} else if (filter == 'completed') {
return completedStream;
} else if (filter == 'active') {
return activeStream;
}
return todoStream;
}
Run Code Online (Sandbox Code Playgroud)
稍后在小部件中使用,如下所示:
return StreamBuilder<List<TodoModel>>(
stream: bloc.filterTodoLs(filter),
builder:(BuildContext context, …Run Code Online (Sandbox Code Playgroud) 我正在使用 BLOC 模式对我的应用程序中的用户进行身份验证。我有一个主 BlocProvider 来包装我的应用程序。并根据身份验证状态构建一个 BlocBuilder。
如果用户未经身份验证,我有入门/介绍屏幕,将导航到登录屏幕。
登录屏幕包装在另一个 BlocProvider 中,其中包含一个用于登录的按钮,并在登录成功时添加登录事件。
问题是当我从入门屏幕导航时,我失去了主要的authenticationBloc上下文。在我推送新屏幕后,我需要做什么才能访问身份验证块。
void main() {
WidgetsFlutterBinding.ensureInitialized();
Bloc.observer = SimpleBlocObserver();
runApp(
MyApp(),
);
}
class AuthenticationWrapper extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: BlocProvider<AuthenticationBloc>(
create: (context) => AuthenticationBloc()..add(AppStarted()),
child: MyApp(),
),
);
}
}
Run Code Online (Sandbox Code Playgroud)
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocListener<AuthenticationBloc, AuthenticationState>(
listener: (context, state) {
if (state is Authenticated) {
_appUserProfileRepository = AppUserProfileRepository();
}
},
child: BlocBuilder<AuthenticationBloc, AuthenticationState>(
builder: (context, state) { …Run Code Online (Sandbox Code Playgroud) 我正在使用 Freezed 在我的 Flutter 应用程序中生成密封数据类。我需要测试它,但我不知道该怎么做。任何想法?这是状态:
@freezed
abstract class LoginState with _$LoginState {
const factory LoginState({
@required Email email,
@required Password password,
@required bool isLoading,
@required bool showErrors,
@required Option<Either<AuthFailure, Unit>> failureOrSuccessOption,
}) = _LoginState;
factory LoginState.initial() => LoginState(
failureOrSuccessOption: none(),
isLoading: false,
showErrors: false,
email: Email(''),
password: Password(''),
);
}
Run Code Online (Sandbox Code Playgroud)
这是我一直在尝试运行的测试:
import 'package:dartz/dartz.dart';
import 'package:exchangecontrol/auth/application/login_cubit/login_cubit.dart';
import 'package:exchangecontrol/auth/domain/auth_repository.dart';
import 'package:mockito/mockito.dart';
import 'package:flutter_test/flutter_test.dart';
class MockLoginWithEmailAndPassword extends Mock implements AuthRepository {}
void main() {
LoginCubit loginCubit;
MockLoginWithEmailAndPassword mockLoginWithEmailAndPassword;
setUp(() {
mockLoginWithEmailAndPassword = MockLoginWithEmailAndPassword(); …Run Code Online (Sandbox Code Playgroud) 在我见过的bloclibrary官方网站文档中,我从未见过他们使用过rx dart。
然而,有时在社区中,他们说一起使用 rx dart 会更好。但我不明白。我使用 firestore 作为后端,但我觉得我根本不需要 rxdart。尽管我努力搜索,但我无法看到使用 rx dart + BLoC 的良好示例项目。
如果将 rx dart 与 BLoC 一起使用有什么好处?我可以看一个例子吗?
我正在编写我的第一个 Flutter 应用程序,并正在努力应对各种状态管理解决方案。我决定从 Provider 开始,但我正在考虑切换到 BLoC。到目前为止,我发现的大多数示例都仅限于相对简单的事情,例如显示项目列表或响应某些按钮按下。就我而言,几乎所有应用程序都专注于设置相当大的数据块。(它基本上是一大堆表单,所有表单都在大型数据结构的不同位上工作。)
目前,所有状态管理都被放在一个提供程序类中,因为其中大部分都非常密切相关。例如,它的最大部分是一个项目列表,然后是该列表的一堆子集。应用程序中的大部分数据操作都在这些子集上。
我一开始并没有真正打算这样做,但我发现自己将实际使用提供程序的代码放在非常接近顶层的位置,然后沿着树传递数据。它违背了 Provider 的初衷,但它减少了重复的代码。例如,我的应用程序中的一个屏幕有一堆卡片,它们都包含非常相似的列表。它们之间的主要区别在于它们的内容来自不同的列表。因此,为了减少重复的代码,我尽可能地概括了卡片和列表,并将必要的数据沿树向下传递。我还传递回调函数来处理诸如编辑项目或将其从列表中删除之类的事情。
这听起来是一个不错的方法吗?事实上,我在树上传递状态和回调对我来说就像一种代码味道,但正如我所提到的,它减少了重复的代码。如果我有一个提供者暴露了很多东西,那又如何呢?我觉得我应该将数据模型与提供者分开,然后拥有多个较小的提供者。如果我要走这条路,BLoC 会比 Provider 更合适吗?如果我能够分解单一提供商,是否可能会提高性能?拥有多个提供商或集团似乎会使保存更改变得复杂,但也许并非如此。你有没有发现这是一个问题?
编辑:我刚刚发现这个问题,它讨论了不同数据的重用提供程序:Flutter Provider。如何拥有同一提供者类型的多个实例?
我以前并没有真正这么想过,但这是我正在努力解决的一个重要问题。我有独立修改的不同列表。它是在多个地方使用的相同小部件(有时在同一屏幕上),并且如果我将所拥有的内容分解成更小的部分,则提供程序中的功能也将是相同的。由于 Provider 是基于类型而不是实例,因此在这种情况下它可能不起作用。
所以,我在Cubit类中做了一个函数,它是从API获取数据。现在,如果我按下按钮,我就可以获得数据。我想让该函数在页面/屏幕打开时自动调用。供您参考,此页面是用户打开应用程序时将启动的第一个页面。这是我的一些代码。
class UsersCubit extends Cubit<UsersState> {
UsersCubit() : super(UsersInitial());
UserRepository _userRepository = UserRepository();
void getAllUsers() async{
emit(UsersLoading());
try{
ResponseUsers _data = await _userRepository.getUsers();
emit(UsersSuccess(_data));
} catch(e){
emit(UsersError(e.toString()));
}
}
}
Run Code Online (Sandbox Code Playgroud)
class UsersPage extends StatefulWidget {
const UsersPage({Key? key}) : super(key: key);
@override
_UsersPageState createState() => _UsersPageState();
}
class _UsersPageState extends State<UsersPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Users")),
body: BlocProvider(
create: (context) => UsersCubit(),
child: BlocConsumer<UsersCubit, UsersState>(
listener: (context, state) {
if(state is UsersLoading){
print("getting users …Run Code Online (Sandbox Code Playgroud) 我有一个对话框,我将其包装在 blocbuilder 中以根据状态类型更新它,但该对话框只是第一次构建,在状态更改后它不会重建。
showDialog(
context: context,
builder: (_) {
BlocBuilder<ExampleCubit, ExampleState>(
bloc: cubit,
builder: (context, state) {
return CustomDialog(
title:"title",
onSave: (File file) {
cubit.uploadImage(file);
},
progress: (state is ExtendedExampleState)? state.progress:0,
onDelete: () {},
onCancel: () {
cubit.cancelUploading();
},
);
},
);
Run Code Online (Sandbox Code Playgroud)
注意:使用 Bloc 模式很重要StateFulBuilder。
bloc ×10
flutter ×10
dart ×3
cubit ×2
events ×1
flutter-bloc ×1
freezed ×1
parameters ×1
stream ×1
unit-testing ×1