在BLoC中触发初始事件 [英] Triggering initial event in BLoC

查看:53
本文介绍了在BLoC中触发初始事件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

example_states:

example_states:

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

class LoadingState extends ExampleState {
  //
}

class LoadedState extends ExampleState {
  //
}

class FailedState extends ExampleState {
  //
}

example_events:

example_events:

abstract class ExampleEvent extends Equatable {
  //
}

class SubscribeEvent extends ExampleEvent {
  //
}

class UnsubscribeEvent extends ExampleEvent {
  //
}

class FetchEvent extends ExampleEvent {
  // 
}

example_bloc:

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:

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()事件触发下一个状态.但是我在那里不舒服.我想做的是:

As you can see in example_bloc, initial state is LoadingState() and in build it shows circular progress bar. I use Fetch() event to trigger next states. But I don't feel comfortable using it there. What I want to do is:

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

When app starts, it should show LoadingState and start networking calls, then when it's all completed, it should show LoadedState with networking call results and FailedState if something goes wrong. I want to achieve these without doing

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

推荐答案

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

Your discomfort really has reason - no event should be fired from build() method (build() could be fired as many times as Flutter framework needs)

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

Our case is to fire initial event on Bloc creation

可能性概述

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

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

create: callback is fired only once when BlocProvider is mounted & BlocProvider would close() bloc when BlocProvider is unmounted

    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的情况
  1. case when you create Bloc in State of Statefull widget

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随时可以通过评论与我联系

PS feel free to reach me in comments

这篇关于在BLoC中触发初始事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆