我刚开始使用 Bloc 和 Cubit,因此我正在尝试找出一些专门针对 State 组件的最佳实践。我有一个简单的待办事项应用程序,其中待办事项可以处于多种不同的状态:
part of 'todos_cubit.dart';
abstract class TodosState extends Equatable {
const TodosState();
@override
List<Object> get props => [];
}
class TodosLoading extends TodosState {}
class TodosLoaded extends TodosState {
final List<Todo> todos;
TodosLoaded(this.todos);
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is TodosLoaded && listEquals(other.todos, todos);
}
@override
int get hashCode => todos.hashCode;
}
class TodosEmpty extends TodosState {}
class TodosError extends TodosState {
final String error;
TodosError(this.error);
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is TodosError && other.error == error;
}
@override
int get hashCode => error.hashCode;
}
我的问题是,我应该将
List<Todo> todos
保留在 TodosLoaded
子类中还是应该将其移动到基类中?我的想法是,通过将其移动到基类,它会使我的 TodosEmpty
状态变得多余,因为我可以简单地检查 UI 中的待办事项列表是否为空。如果是这样的话,我是否也应该将 String error
移至基类?
我确信每种方法都有优点和缺点,只是希望能向对 Bloc 有更多经验的人提出想法。
尝试使用Cubit,它大大简化了代码。
我可能会在 cubit 类中创建一个函数
addToDo(todoItem)
和 removeToDo(todoItem)
来更新列表并发出更改。列表变量将以肘为单位,您将使用 context.read<TodoCubit>().todoList
从小组件中引用此列表。
您将使用如下功能:
context.read<TodoCubit>().addToDo(todoItem)
我已经编写了 Cubit 实现最佳方法的教程 Flutter |使用 Cubit (Bloc) 进行 Firebase 身份验证 — 教程 1(共 2)
我认为这篇文章会对您有很大帮助。快来看看🤓
对于检查此线程的人来说,在待办事项列表中显示
TodosEmpty
和 TodosLoaded
等状态是非常好的。尽管如此,我会使用 freezed 包并简化它,就像我在我的应用程序中所做的那样:
“books_list_cubit.dart”的一部分;
@freezed
class BooksListPageState with _$BooksListPageState {
const factory BooksListPageState.loading() = BooksListPageLoading;
const factory BooksListPageState.empty() = BooksListPageEmpty;
const factory BooksListPageState.success(List<Book> books) = BooksListPageSuccess;
}
有关此内容的更多信息,请参阅我的 Flutter 肘部 + 钩子 + Hive DB 教程。
准备您的项目,例如: 库/ ├── 肘/ │ ├── api_cubit.dart │ ├── api_state.dart ├── 经理/ │ └── api_manager.dart ├── 型号/ │ └── user_model.dart ├── 画面/ │ └── home_screen.dart └── main.dart user_model.dart
class User {
final int id;
final String name;
final String email;
User({required this.id, required this.name, required this.email});
factory User.fromJson(Map<String, dynamic> json) {
return User(
id: json['id'],
name: json['name'],
email: json['email'],
);
}
}
api_manager.dart //创建一个类来处理API调用
导入'package:dio/dio.dart'; 导入'../models/user_model.dart';
类 ApiManager { 最终 Dio _dio = Dio();
未来 fetchUsers() 异步 {
尝试 {
最终响应=await_dio.get('https://jsonplaceholder.typicode.com/users');
return (response.data as List).map((user) => User.fromJson(user)).toList();
} 捕获 (e) {
throw Exception('获取用户失败');
}
}
}
api_cubit.dart,定义Cubit来管理状态
import 'package:flutter_bloc/flutter_bloc.dart';
import '../manager/api_manager.dart';
import '../models/user_model.dart';
import 'api_state.dart';
class ApiCubit extends Cubit<ApiState> {
final ApiManager apiManager;
ApiCubit({required this.apiManager}) : super(ApiInitial());
Future<void> fetchUsers() async {
emit(ApiLoading());
try {
final users = await apiManager.fetchUsers();
emit(ApiLoaded(users: users));
} catch (e) {
emit(ApiError(message: e.toString()));
}
}
}
api_state.dart, define the states for the Cubit
import '../models/user_model.dart';
abstract class ApiState {}
class ApiInitial extends ApiState {}
class ApiLoading extends ApiState {}
class ApiLoaded extends ApiState {
final List<User> users;
ApiLoaded({required this.users});
}
class ApiError extends ApiState {
final String message;
ApiError({required this.message});
}
构建 UI 以显示获取的数据
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../cubit/api_cubit.dart';
import '../cubit/api_state.dart';
import '../manager/api_manager.dart';
class HomeScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => ApiCubit(apiManager: ApiManager())..fetchUsers(),
child: Scaffold(
appBar: AppBar(title: Text('Users')),
body: BlocBuilder<ApiCubit, ApiState>(
builder: (context, state) {
if (state is ApiLoading) {
return Center(child: CircularProgressIndicator());
} else if (state is ApiLoaded) {
return ListView.builder(
itemCount: state.users.length,
itemBuilder: (context, index) {
final user = state.users[index];
return ListTile(
title: Text(user.name),
subtitle: Text(user.email),
);
},
);
} else if (state is ApiError) {
return Center(child: Text(state.message));
}
return Center(child: Text('Press the button to fetch users.'));
},
),
),
);
}
}
您可以将获取的数据存储在本地(例如,使用像shared_preferences这样的包)并在进行新的API调用之前从缓存加载它。