从 v7.2.1 迁移到 flutter_bloc v 8.0.0 后不会触发 flutter_bloc 事件

Posted

技术标签:

【中文标题】从 v7.2.1 迁移到 flutter_bloc v 8.0.0 后不会触发 flutter_bloc 事件【英文标题】:flutter_bloc event is not trigger after Migrate to flutter_bloc v 8.0.0 from v7.2.1 【发布时间】:2021-12-31 09:34:26 【问题描述】:

我尝试迁移 flutter_bloc v 8.0.0。阅读文档后,我知道我需要将 mapEventToState 迁移到 on。之后我没有收到错误但 _getMonks 事件没有触发。这是我的代码。有什么我错过的吗?

class MonkBloc extends Bloc<MonkEvent, MonkState> 
   final MonkRespository monkRespository;
   late List<Monk> monks;

   MonkBloc(required this.monkRespository) : super(MonkInitial()) 
       on<GetMonksEvent>((event, emit) => _getMonks);
       on<MonkSearchEvent>((event, emit) => _searchMonks);
   

   Stream<MonkState> _getMonks(Emitter<MonkState> emit) async* 
     emit(MonkLoading());
     try 
        final List<Monk> monks = await monkRespository.fetchMonks();
        emit(MonkLoaded(monks: monks));
      catch (e) 
     emit (MonkError(error: (e.toString())));
     
  

  Stream<MonkState> _searchMonks(String query, Emitter<MonkState> emit) async* 
emit(MonkLoading());
try 
  final List<Monk> monks = await monkRespository.searchMonks(query);
  emit(MonkLoaded(monks: monks));
 catch (e) 
  emit(MonkError(error: (e.toString())));




class MonkScreen extends StatefulWidget 
  static const routeName = '/monk';
  final String? title;
  final MonkScreenMode? screenMode;
  const MonkScreen(Key? key, this.title, this.screenMode) : super(key: key);

  @override
  State<MonkScreen> createState() => _MonkScreenState();
  

  class _MonkScreenState extends State<MonkScreen> 

  _loadMonks() async 

    BlocProvider.of<MonkBloc>(context).add(const GetMonksEvent()); 
     

  @override
  void initState() 
    super.initState();
    _loadMonks();
  

  @override
  Widget build(BuildContext context) 
  return BaseWidget(
  child: Scaffold(
    backgroundColor: Theme.of(context).backgroundColor,
    appBar: AppBar(
      centerTitle: true,
      backgroundColor: Theme.of(context).backgroundColor,
      elevation: 0,
      title: AutoSizeText(
        widget.title!,
        style: Theme.of(context).appBarTheme.titleTextStyle,
      ),
      leading: IconButton(
        onPressed: () 
          Navigator.pop(context);
        ,
        icon: Icon(
          Icons.arrow_back,
          color: Theme.of(context).primaryIconTheme.color!,
        ),
      ),
      actions: [
        IconButton(
          onPressed: () 
            showSearch(
                context: context,
                delegate: MonkSearch(screenMode: widget.screenMode!));
          ,
          icon: Icon(
            Icons.search,
            color: Theme.of(context).primaryIconTheme.color!,
          ),
        ),
      ],
    ),
    body: BlocBuilder<MonkBloc, MonkState>(
      builder: (BuildContext context, MonkState monkState) 
        if (monkState is MonkError) 
          return const SomethingWentWrongScreen();
         else if (monkState is MonkLoaded) 
          return listViewBuilder(
              context, monkState.monks, widget.screenMode!);
        
        return const Center(
          child: CircularProgressIndicator(),
        );
      ,
    ),
  ),
);


【问题讨论】:

【参考方案1】:

这就是我迁移代码的方式。以防有人需要。

class MonkBloc extends Bloc<MonkEvent, MonkState> 
final MonkRespository monkRespository;
late List<Monk> monks;

MonkBloc(required this.monkRespository) : super(MonkInitial()) 
on<GetMonksEvent>((event, emit) async 
await _getMonks(emit);
);
on<MonkSearchEvent>((event, emit) async 
await _searchMonks(event.query, emit);
);


 Future<void> _getMonks(Emitter<MonkState> emit) async 
 emit(MonkLoading());
 try 
 final List<Monk> monks = await monkRespository.fetchMonks();
  emit(MonkLoaded(monks: monks));
  catch (e) 
 emit (MonkError(error: (e.toString())));
 
 

 Future<void> _searchMonks(String query, Emitter<MonkState> emit) async 
 
 emit(MonkLoading());
  try 
  final List<Monk> monks = await monkRespository.searchMonks(query);
 emit(MonkLoaded(monks: monks));
  catch (e) 
 emit(MonkError(error: (e.toString())));
 
 
 

【讨论】:

【参考方案2】:
class APIBloc extends Bloc<APIEvents, APIState> 
  //
  final APIRepo apiRepo;

  APIBloc(required this.apiRepo) : super(APIInitState()) 
    on<APIEvents>(_addToValue);
  

  Future<void> _addToValue(APIEvents event, Emitter<APIState> emit) async 
    print("onEvent");
    emit(APILoading());
    emit.forEach(
        Stream.fromFuture(_callAPI(event).catchError((onError) 
          return onError;
        )), onData: (value) 
      if (value is Response)
        return APILoaded(response: value as Response);
      else 
        return value as APIListError;
      
    );
  

  Future<Object> _callAPI(APIEvents event) async 
    try 
      if (event is FetchDashBoard) 
        return await apiRepo.getDashboardData(event.requestParams);
       else if (event is DoLogin) 
        return await apiRepo.doLogin(event.requestParams);
       else 
        throw (APIListError(
          error: NoInternetException('No Internet'),
        ));
      
     on SocketException 
      throw (APIListError(
        error: NoInternetException('No Internet'),
      ));
     on HttpException 
      throw (APIListError(
        error: NoServiceFoundException('No Service Found'),
      ));
     on FormatException 
      throw (APIListError(
        error: InvalidFormatException('Invalid Response format'),
      ));
     catch (e) 
      throw (APIListError(
        error: UnknownException('Unknown Error'),
      ));
    
  

如果需要更多澄清代码,请关注以下站点。 https://flutterlearneasyway.blogspot.com/2021/11/flutter-bloc-pattern-800-call-api.html

【讨论】:

【参考方案3】:

这里有错别字。

on&lt;GetMonksEvent&gt;((event, emit) =&gt; _getMonks);

您必须使用 args 调用 _getMonks 或仅传递事件侦听器本身:

用这个

on<GetMonksEvent>((event, emit) => _getMonks(event, emit));

或者更好的

on<GetMonksEvent>(_getMonks);

【讨论】:

以上是关于从 v7.2.1 迁移到 flutter_bloc v 8.0.0 后不会触发 flutter_bloc 事件的主要内容,如果未能解决你的问题,请参考以下文章

Flutter_bloc 从没有 UI 事件的 firestore 获取更新的数据

将flutter_bloc与tabview一起使用

flutter_bloc(在事件处理程序正常完成后调用发出

flutter_bloc - 每个 Bloc 有多个存储库,还是只有一个?

使用 flutter_bloc 库有啥缺点

博科300交换机不中断(non-disruptive)固件升级