Search code examples
androidflutterdartblocmigrate

Flutter how to migrate this BLoC old version code to Bloc new version


how i must write this code in bloc v.8 i don know how i see some searches but im not understand and this is my code for classes they give me error => StateError (Bad state: add(DoFetchEvent) was called without a registered event handler. Make sure to register a handler via on((event, emit) {...})):

 class PostBloc extends Bloc<PostEvent, PostState> {
           PostRepository repo;

        PostBloc(PostState initialState, this.repo) : super(initialState);

      Stream<PostState> mapEventToState(PostEvent event) async* {
           if (event is DoFetchEvent) {
         yield LoadingState();
       try {
      var posts = await repo.fetchPosts();
       yield FetchSuccess(posts: posts);
     } catch (e) {
    yield ErrorState(message: e.toString());
     }
   }
   }
  }

import 'package:equatable/equatable.dart';

 class PostEvent extends Equatable {
 @override
 List<Object?> get props => [];
}

class DoFetchEvent extends PostEvent {}

   class PostState extends Equatable {
       @override
        
      List<Object?> get props => [];
     }

     class InitialState extends PostState {}

     class LoadingState extends PostState {}

       class FetchSuccess extends PostState {
             List<PostModel> posts;

            FetchSuccess({required this.posts});
           }

         class ErrorState extends PostState {
         String message;
      ErrorState({required this.message});
             }

   void main() {
 runApp(MaterialApp(
  home: BlocProvider(
  create: (context) => PostBloc(InitialState(), PostRepository()),
     child: MyApp(),
   ),
 ));
  }

Solution

  • You can set your InitialState directly in the super constructor without manually passing it in like so.

     PostBloc(this.repo) : super(InitialState()) {
        on<DoFetchEvent>(_onDoFetchEvent);
      }
    

    Then you no longer pass in any state in the BlocProvider

     BlocProvider<PostBloc>(
              create: (BuildContext context) => PostBloc(PostRepository()),
    ...
    

    Then your mapEventToState gets replaced with a method that takes the relevant event, and an Emitter<PostState> as arguments. yield then gets replaced with emit in the method.

    Your whole class would look like this.

      PostBloc(this.repo) : super(InitialState()) {
        on<DoFetchEvent>(_onDoFetchEvent);
      }
    
      _onDoFetchEvent(
        DoFetchEvent event,
        Emitter<PostState> emit,
      ) async {
        emit(LoadingState());
        try {
          var posts = await repo.fetchPosts();
          emit(FetchSuccess(posts: posts));
        } catch (e) {
          emit(ErrorState(message: e.toString()));
        }
      }
    }
    

    That should do it.

    Besides that, you're probably getting linter warnings about must_be_immutable on your state classes because PostState extend Equatable.

    So I suggest making all PostState parameters final and adding the props override from Equatable to your state classes.

    class ErrorState extends PostState {
      final String message;
      ErrorState({required this.message});
    
      @override
      List<Object?> get props => [message];
    }