Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why this BlocBuilder do not rebuild my list after second trigger?

I have cubit in which I download movies and pass it to the list:

class MovieSearchCubit extends Cubit<MovieState> {
  MovieSearchRepoInterface movieSearchRepository;
  List<Movie> emptyList = [];

  MovieSearchCubit({required this.movieSearchRepository})
      : super(const MovieState());

  Future<void> fetchMovies(String movieName) async {

    if (state.status != MovieStatus.failure) {
      final movies = await movieSearchRepository.searchMovies(movieName);

      if (movies.isRight()) {
    

        emit(state.copyWith(
            status: MovieStatus.success,
            posts: List.of(state.movies)
              ..addAll(
                movies.getOrElse((l) => emptyList),
              )));
      } else {
        emit(state.copyWith(status: MovieStatus.failure));
      }
    }
  }
}

and I'm calling it in BlocBuilder like this:

    BlocBuilder<MovieSearchCubit, MovieState>(
                    builder: (context, state) {
                  switch (state.status) {
                    case MovieStatus.failure:
                      return const Center(child: Text('failed to fetch posts'));
                    case MovieStatus.success:
                      if (state.movies.isEmpty) {
                        return const Center(child: Text('no posts'));
                      }
                      return Expanded(
                        child: ListView.builder(
                          shrinkWrap: true,
                          itemBuilder: (BuildContext context, int index) {
                            return index >= state.movies.length
                                ? BottomLoader()
                                : MovieCard(
                                    });
                          },
                          itemCount: state.movies.length,
                        ),
                      );

                    default:
                      return Container();
                  }
                }),

I'm triggering cubit function fetchMovies by pressing button:

IconButton(
                      icon: const Icon(Icons.search),
                      onPressed: () async {
                        await context.read<MovieSearchCubit>().fetchMovies(inputStr);
                      },
                    ),

But the list is build only the first time, data is gathered correctly, the problem is with displaying it. Thanks for any tips.

Added later: Here how looks like MovieState

 class MovieState extends Equatable {
  const MovieState({
    this.status = MovieStatus.initial,
    this.movies = const <Movie>[],
  });

  final MovieStatus status;
  final List<Movie> movies;

  MovieState copyWith({
    MovieStatus? status,
    List<Movie>? posts,
  }) {
    return MovieState(
      status: status ?? this.status,
      movies: posts ?? this.movies,
    );
  }

  @override
  List<Object?> get props => [];
}
like image 905
Dawid Twin Avatar asked Nov 24 '25 22:11

Dawid Twin


1 Answers

BLoC new state is only emitted when oldState != newState this means that we need a way to correctly differentiate between two instances of the state, we have two ways here, or by overriding the equals operator of your state, or like in your case we may use Equatable to have an easy way to check for equality.

class MovieState extends Equatable {
  const MovieState({
    this.status = MovieStatus.initial,
    this.movies = const <Movie>[],
  });

  final MovieStatus status;
  final List<Movie> movies;

  MovieState copyWith({
    MovieStatus? status,
    List<Movie>? posts,
  }) {
    return MovieState(
      status: status ?? this.status,
      movies: posts ?? this.movies,
    );
  }

  @override
  List<Object?> get props => []; <--- Missing props
}

Your class however is missing the props, so any instance of MovieState will be equal! and the state will be emitted only once, the easy fix here is to add the property to your props methods in order to have a proper check

  @override
  List<Object?> get props => [status, movies];
like image 169
CLucera Avatar answered Nov 27 '25 00:11

CLucera



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!