屏幕加载时如何仅调用一次 bloc 事件

Posted

技术标签:

【中文标题】屏幕加载时如何仅调用一次 bloc 事件【英文标题】:How to call bloc event only once when the screen loads 【发布时间】:2020-12-10 23:43:45 【问题描述】:

我正在使用flutter_bloc 库。我的屏幕小部件代码如下所示:

class RegisterScreen extends StatefulWidget 
  RegisterScreen();

  @override
  _RegisterScreenState createState() => _RegisterScreenState();


class _RegisterScreenState extends State<RegisterScreen> 
  @override
  Widget build(BuildContext context) 
    return BlocProvider<RegisterBloc>(
      create: (BuildContext context) 
        // RegisterBloc.get(context).add(RegisterGetCitiesEvent());<=== This gives me error `BlocProvider.of() called with a context that does not contain a Cubit of type RegisterBloc. \n No ancestor could be found starting from the context that was passed to BlocProvider.of<RegisterBloc>().`
        return RegisterBloc();
      ,
      child: BlocConsumer<RegisterBloc, RegisterState>(
        listener: (BuildContext context, RegisterState state) ,
        builder: (BuildContext context, RegisterState state) 
          // RegisterBloc.get(context).add(RegisterGetCitiesEvent());<=== This line is executed infinite times
          return Scaffold(
            floatingActionButton: FloatingActionButton(
              onPressed: () 
                RegisterBloc.get(context).add(RegisterGetCitiesEvent());
              ,
              child: new Icon(Icons.refresh),
            ),
            body: Conteiner(
              child: Text(RegisterBloc.get(context).cities==null?'':RegisterBloc.get(context).cities,)
            ),
          );
        ,
      ),
    );
  

bloc文件是这样的:

class RegisterBloc extends Bloc<RegisterEvent, RegisterState> 
  static RegisterBloc get(BuildContext context) => BlocProvider.of(context);
  RegisterBloc() : super(RegisterInitial());

  String cities = '';

  @override
  Stream<RegisterState> mapEventToState(
    RegisterEvent event,
  ) async* 
    if (event is RegisterGetCitiesEvent) 
      yield* getCities();
    
  

  Stream<RegisterGetCitiesState> getCities() async* 
    yield await (CustomerServer.getCities()).then((res) 
      cities = res;
      return RegisterGetCitiesState();
    );
  

在我的代码中,我必须点击FAB 来调用RegisterGetCitiesEvent bloc 事件。如何在不要求用户单击任何按钮的情况下立即调用该事件RegisterBloc.get(context).add(RegisterGetCitiesEvent())

我尝试了什么:

我尝试在 BlocConsumer 构建器函数中添加该行,但该函数执行了无限次。 我试图在BlocProvider 创建函数中添加该行,但它给了我一个错误BlocProvider.of() called with a context that does not contain a Cubit of type RegisterBloc.

我应该把这行RegisterBloc.get(context).add(RegisterGetCitiesEvent())放在哪里,以便在屏幕显示时自动调用RegisterGetCitiesEvent事件(无需点击任何按钮)?

【问题讨论】:

【参考方案1】:

我建议您完整阅读BLoC 文档。但这里是对这个问题的快速回答:您应该在BlocProvider 的创建函数中这样做。像这样:

class RegisterScreen extends StatefulWidget 
  RegisterScreen();

  @override
  _RegisterScreenState createState() => _RegisterScreenState();


class _RegisterScreenState extends State<RegisterScreen> 
  @override
  Widget build(BuildContext context) 
    return BlocProvider<RegisterBloc>(
      create: (context) => RegisterBloc()..add(RegisterGetCitiesEvent())
    );
  

【讨论】:

谢谢@Amir_P,在上面的例子中,RegisterGetCitiesEvent() 事件是否会在每次将这个RegisterScreen 推送到导航堆栈时触发? 是的,它会被称为@Mikethetechy

以上是关于屏幕加载时如何仅调用一次 bloc 事件的主要内容,如果未能解决你的问题,请参考以下文章

Flutter BLoC mapEventToState 仅在事件的第一次调用时才被调用,并且不会在下次触发该事件时调用

颤振:如何使用“等待”等待其他 BLoC 事件完成

Flutter BLoC 模式 - 如何在流事件后导航到另一个屏幕?

使用 bloc 更改屏幕

更新身份验证状态时未调用 Bloc 侦听器?

BlocBuilder 构建器函数仅被调用一次