0

I am creating an async counter app in flutter using BLoC (cubit). When I emit a loading state, the counter is not incrementing but returns to 0. How to fix this problem?

Code:

import 'dart:async';

import 'package:bloc/bloc.dart';
import 'package:meta/meta.dart';

part 'counter_state.dart';
class CounterCubit extends Cubit<CounterState> {
  CounterCubit() : super(Counter(counter: 0));

  void increment() {
    print('before CounterLoading() ${state.counter}');
    emit(CounterLoading());
    print('after CounterLoading() ${state.counter}');

    Timer(Duration(seconds: 2), () {
      emit(CounterLoaded());
      print('enter code hereprevious  state ${state.counter}');
      emit(Counter(counter: state.counter + 1));
      print('next state ${state.counter}');
    });
  }
}

part of 'counter_cubit.dart';

@immutable
abstract class CounterState {
  final int counter = 0;
}

class Counter extends CounterState {
  final int counter;
    
  Counter({this.counter});
}

class CounterLoading extends CounterState {
  CounterLoading();
}

class CounterLoaded extends CounterState {
  CounterLoaded();
}
mkobuolys
  • 4,499
  • 1
  • 11
  • 27

1 Answers1

0

The problem is that your other states do not contain the constructor with counter value. As a result, the default value is used from the abstract class - 0. In order to maintain the state, you should set the counter value in all the states. Here is the reworked states code:

@immutable
abstract class CounterState {
  final int counter;
  
  CounterState({this.counter = 0});
}

class Counter extends CounterState {
  // you do not need the counter property here, it is defined in the base class    
    
  Counter({required int counter}) : super(counter: counter);
}

class CounterLoading extends CounterState {
  CounterLoading({required int counter}) : super(counter: counter);
}

class CounterLoaded extends CounterState {
  CounterLoaded({required int counter}) : super(counter: counter);
}

And adjust your cubit accordingly:

class CounterCubit extends Cubit<CounterState> {
  CounterCubit() : super(Counter(counter: 0));

  void increment() {
    print('before CounterLoading() ${state.counter}');
    emit(CounterLoading(counter: state.counter));
    print('after CounterLoading() ${state.counter}');

    Timer(Duration(seconds: 2), () {
      emit(CounterLoaded(counter: state.counter));
      print('enter code hereprevious  state ${state.counter}');
      emit(Counter(counter: state.counter + 1));
      print('next state ${state.counter}');
    });
  }
}
mkobuolys
  • 4,499
  • 1
  • 11
  • 27
  • Understand. But as you see there is a lot of code duplication is there any simplest way ? Is it necessary every time for every state make a super call ? – Farrukh Zokirov May 23 '21 at 19:34
  • I refactored the states code to avoid that duplication. If you want to have separate states (loading, loaded, counter), that's a way to go. However, from what you want to achieve, only having a single Counter state with the counter property should be enough. – mkobuolys May 23 '21 at 19:37
  • if in state will be more than one field about 10 field suppose should i write super call for every field to not loose current state ? – Farrukh Zokirov May 23 '21 at 19:39
  • If all the states share the same property (properties) that must be maintained - yes, since you need to call `super()` to access the base constructor. – mkobuolys May 23 '21 at 19:42