1

我正在使用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;
}

在上面的代码片段中,我的意图是在出现错误或小部件正在加载时不显示任何数据,但我仍然希望在成功加载或用户正在刷新小部件时显示数据。所以ResultsReportSuccessResultsReportRefreshing状态有一个共享状态,即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());
              },
            ),
          );
        }
      },
    );
  }
}

但是我想知道为什么需要进行类型转换,因为它感觉很麻烦。任何人可以就如何以不同方式实现我的共享状态目标提供任何见解,当然都是受欢迎的。

4

0 回答 0