在BLoC中触发初始事件

时间:2020-06-29 23:24:04

标签: flutter dart bloc flutter-bloc

example_states:

abstract class ExampleState extends Equatable {
  const ExampleState();
}

class LoadingState extends ExampleState {
  //
}

class LoadedState extends ExampleState {
  //
}

class FailedState extends ExampleState {
  //
}

example_events:

abstract class ExampleEvent extends Equatable {
  //
}

class SubscribeEvent extends ExampleEvent {
  //
}

class UnsubscribeEvent extends ExampleEvent {
  //
}

class FetchEvent extends ExampleEvent {
  // 
}

example_bloc:

class ExampleBloc extends Bloc<ExampleEvent, ExampleState> {
  @override
  ExampleState get initialState => LoadingState();

  @override
  Stream<ExampleState> mapEventToState(
    ExampleEvent event,
  ) async* {
    if (event is SubscribeEvent) {
      //
    } else if (event is UnsubscribeEvent) {
      //
    } else if (event is FetchEvent) {
      yield LoadingState();
      try {
        // network calls
        yield LoadedState();
      } catch (_) {
        yield FailedState();
      }
    }
  }
}

example_screen:

class ExampleScreenState extends StatelessWidget {
  // ignore: close_sinks
  final blocA = ExampleBloc();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: BlocBuilder<ExampleBloc, ExampleState>(
        bloc: blocA,
        // ignore: missing_return
        builder: (BuildContext context, state) {
          if (state is LoadingState) {
            blocA.add(Fetch());
            return CircularProgressBar();
          }

          if (state is LoadedState) {
            //...
          }

          if (state is FailedState) {
            //...
          }
        },
      ),
    );
  }
}

在example_bloc中可以看到,初始状态为LoadingState(),在构建中它显示循环进度条。我使用Fetch()事件触发下一个状态。但是我在那里不舒服。我想做的是:

应用启动时,它应该显示LoadingState并开始网络调用,然后当它们全部完成时,它应该显示带有网络调用结果的LoadedState以及出现问题时的FailedState。我想不做就实现这些

if (state is LoadingState) {
  blocA.add(Fetch());
  return CircularProgressBar();
}

1 个答案:

答案 0 :(得分:14)

您的不适确实有原因-build()方法中不应触发任何事件(build()可以根据Flutter框架需要触发多次)

我们的情况是在创建Bloc时触发初始事件

可能性概述

  1. 使用BlocProvider插入Bloc的情况-这是首选方式

create:回调仅在安装BlocProvider时触发一次,并且在卸载BlocProvider时BlocProvider会关闭()bloc

    class ExampleScreenState extends StatelessWidget {
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: BlocProvider(
            create: (context) => ExampleBloc()..add(Fetch()), // <-- first event, 
            child: BlocBuilder<ExampleBloc, ExampleState>(
              builder: (BuildContext context, state) {
                ...
              },
            ),
          ),
        );
      }
    }
  1. 在Statefull小部件的State中创建Bloc的情况
class _ExampleScreenStateState extends State<ExampleScreenState> {
  ExampleBloc _exampleBloc;

  @override
  void initState() {
    super.initState();
    _exampleBloc = ExampleBloc();
    _exampleBloc.add(Fetch());
    // or use cascade notation
    // _exampleBloc = ExampleBloc()..add(Fetch());
  }

  @override
  void dispose() {
    super.dispose();
    _exampleBloc.close(); // do not forget to close, prefer use BlocProvider - it would handle it for you
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: BlocBuilder<ExampleBloc, ExampleState>(
        bloc: _exampleBloc,
        builder: (BuildContext context, state) {
         ...
        },
      ),
    );
  }
}
  1. 在创建Bloc实例时添加第一个事件-由于第一个事件是隐式的,因此这种方法在测试时有缺点
class ExampleBloc extends Bloc<ExampleEvent, ExampleState> {

  ...

  ExampleBloc() {
    add(Fetch());
  }
}

// insert it to widget tree with BlocProvider or create in State
BlocProvider( create: (_) => ExampleBloc(), ...

// or in State

class _ExampleScreenStateState extends State<ExampleScreenState> {
  final _exampleBloc = ExampleBloc(); 
...

PS随时可以通过评论与我联系