我正在使用freezed包来生成由bloc library使用的状态对象。
我喜欢为小部件的状态定义联合类的能力,这样我就可以表达小部件所具有的不同且通常不相交的状态。例如:
@freezed
class ResultsReportState with _$ResultsReportState {
const factory ResultsReportState.loading() = ResultsReportLoading;
const factory ResultsReportState.success({
required ReportViewViewModel report,
}) = ResultsReportSuccess;
const factory ResultsReportState.refreshing({
required ReportViewViewModel report,
}) = ResultsReportRefreshing;
const factory ResultsReportState.error() = ResultsReportError;
}
在上面的代码片段中,我的意图是在出现错误或小部件正在加载时不显示任何数据,但我仍然希望在成功加载或用户正在刷新小部件时显示数据。所以ResultsReportSuccess
和ResultsReportRefreshing
状态有一个共享状态,即ReportViewViewModel
。但是,即使按照此处的建议执行类型检查,我也无法访问这些共享属性。
例如,如果没有显式类型转换,这将不起作用:
class ResultsReport extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocBuilder<ResultsReportBloc, ResultsReportState>(
builder: (context, state) {
if (state is ResultsReportSuccess || state is ResultsReportRefreshing) {
return SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
var serviceCategory = state.report.serviceCategories[index];
return ServiceCategoryBlock(
viewModel: serviceCategory,
);
},
childCount: state.report.serviceCategories.length,
),
);
} else if (state is ResultsReportLoading) {
return ResultsScreenLoadingSkeleton();
} else {
return SliverFillRemaining(
child: ErrorStateContent(
onErrorRetry: () {
context
.read<ResultsReportBloc>()
.add(ResultsReportEvent.retryButtonTapped());
},
),
);
}
},
);
}
}
但是我没有什么可以明确类型转换的,因为它可以是任何一种类型。所以,我尝试了这种方法,它引入了一个我可以参考的接口:
part of 'results_report_bloc.dart';
abstract class ReportPopulated {
ReportViewViewModel get report;
}
@freezed
class ResultsReportState with _$ResultsReportState {
const factory ResultsReportState.loading() = ResultsReportLoading;
@Implements<ReportPopulated>()
const factory ResultsReportState.success({
required ReportViewViewModel report,
}) = ResultsReportSuccess;
@Implements<ReportPopulated>()
const factory ResultsReportState.refreshing({
required ReportViewViewModel report,
}) = ResultsReportRefreshing;
const factory ResultsReportState.error() = ResultsReportError;
}
class ResultsReport extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocBuilder<ResultsReportBloc, ResultsReportState>(
builder: (context, state) {
if (state is ReportPopulated) {
return SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
var serviceCategory = state.report.serviceCategories[index];
return ServiceCategoryBlock(
viewModel: serviceCategory,
);
},
childCount: state.report.serviceCategories.length,
),
);
} else if (state is ResultsReportLoading) {
return ResultsScreenLoadingSkeleton();
} else {
return SliverFillRemaining(
child: ErrorStateContent(
onErrorRetry: () {
context
.read<ResultsReportBloc>()
.add(ResultsReportEvent.retryButtonTapped());
},
),
);
}
},
);
}
}
但这也需要类型转换。所以,我可以这样做:
class ResultsReport extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocBuilder<ResultsReportBloc, ResultsReportState>(
builder: (context, state) {
if (state is ReportPopulated) {
ReportPopulated currentState = state as ReportPopulated;
return SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
var serviceCategory = currentState.report.serviceCategories[index];
return ServiceCategoryBlock(
viewModel: serviceCategory,
);
},
childCount: currentState.report.serviceCategories.length,
),
);
} else if (state is ResultsReportLoading) {
return ResultsScreenLoadingSkeleton();
} else {
return SliverFillRemaining(
child: ErrorStateContent(
onErrorRetry: () {
context
.read<ResultsReportBloc>()
.add(ResultsReportEvent.retryButtonTapped());
},
),
);
}
},
);
}
}
但是我想知道为什么需要进行类型转换,因为它感觉很麻烦。任何人可以就如何以不同方式实现我的共享状态目标提供任何见解,当然都是受欢迎的。