UI Not updating on bloc state change


I am new in using bloc library with freezed package. I have a scenario where a list of objects is coming from API is displayed. Now the list tile has a Marked as Fav button and clicking upon it a event is trigged and fav bool is toggled and state is emitted.

The Issue :
The value of the object is changed but the UI is not updated accordingly.


import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_bloc_update/bloc/fakeapi_bloc.dart';

void main() {
      create: (context) => FakeapiBloc(),
      child: const MyApp(),

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // This widget is the root of your application.
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      home: const Scaffold(
        body: SafeArea(child: MyHomePage()),

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key}) : super(key: key);

  State<MyHomePage> createState() => _MyHomePageState();

class _MyHomePageState extends State<MyHomePage> {
  void initState() {
    context.read<FakeapiBloc>().add(const FakeapiEvent.loadData());

  Widget build(BuildContext context) {
    return BlocBuilder<FakeapiBloc, FakeapiState>(
      builder: (context, state) {
        return state.map(
          inital: (_) => const Center(
            child: CircularProgressIndicator(),
          loading: (_) => const Center(
            child: CircularProgressIndicator(),
          loaded: (state) {
            return ListView.builder(itemBuilder: (ctx, pos) {
              return ListTile(
                title: Text(state.posts[pos].title),
                trailing: IconButton(
                  onPressed: () {
                        .add(FakeapiEvent.markedFav(pos: pos));
                  icon: Icon(state.posts[pos].isFav
                      ? Icons.favorite
                      : Icons.favorite_border_outlined),
          error: (_) => const Center(
            child: CircularProgressIndicator(),


import 'dart:convert';

List<Post> postFromJson(String str) =>
    List<Post>.from(json.decode(str).map((x) => Post.fromJson(x)));

String postToJson(List<Post> data) =>
    json.encode(List<dynamic>.from(data.map((x) => x.toJson())));

class Post {
    required this.userId,
    required this.id,
    required this.title,
    required this.body,

  final int userId;
  final int id;
  final String title;
  final String body;
  bool isFav = false;

  factory Post.fromJson(Map<String, dynamic> json) => Post(
        userId: json["userId"],
        id: json["id"],
        title: json["title"],
        body: json["body"],

  Map<String, dynamic> toJson() => {
        "userId": userId,
        "id": id,
        "title": title,
        "body": body,


import 'package:bloc/bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:freezed_bloc_update/post.dart';
import 'package:http/http.dart' as http;

part 'fakeapi_event.dart';
part 'fakeapi_state.dart';
part 'fakeapi_bloc.freezed.dart';

class FakeapiBloc extends Bloc<FakeapiEvent, FakeapiState> {
  FakeapiBloc() : super(const FakeapiState.inital()) {
      (event, emit) async {
        try {
          emit(const FakeapiState.loading());
          Uri uri = Uri.parse('https://jsonplaceholder.typicode.com/posts');
          final response = await http.get(uri);
          if (response.statusCode == 200) {
            emit(FakeapiState.loaded(posts: postFromJson(response.body)));
          } else {
            emit(const FakeapiState.error(errorMessage: 'Api Call Failed'));
        } catch (err) {
          emit(const FakeapiState.error(errorMessage: 'Api Call Failed'));

    on<MarkedFav>((event, emit) {
      final previousState = state as Loaded;
      previousState.posts[event.pos].isFav =
      emit(FakeapiState.loaded(posts: [...previousState.posts]));


part of 'fakeapi_bloc.dart';

class FakeapiEvent with _$FakeapiEvent {
  const factory FakeapiEvent.loadData() = LoadData;
  const factory FakeapiEvent.markedFav({required int pos}) = MarkedFav;


part of 'fakeapi_bloc.dart';

class FakeapiState with _$FakeapiState {
  const factory FakeapiState.inital() = Initial;
  const factory FakeapiState.loading() = Loading;
  const factory FakeapiState.loaded({required List<Post> posts}) = Loaded;
  const factory FakeapiState.error({required String errorMessage}) = Error;

One solution which I did was keeping a bool variable(outside of model class) in state itself and clicking upon the fav toggling the bool value. Which is retriggering the UI update.


your Post class should be converted to a freezed class

Answered By – Mahmoud Abdellatief

Answer Checked By – Robin (FlutterFixes Admin)

Leave a Reply

Your email address will not be published. Required fields are marked *