skip to Main Content

I’m trying to trigger an update when a list in my map changes. Type is Map<String, List<int>>. Basically one of the integers is changing in the list but not triggering the blocbuilder. Although when I print the state the value is updated. I’m using freezed. From what I understand freezed only provides deep copies for nested @freezed objects but not for Iterables. I’ve seen a few solutions for this kind of problem. For example create a new Map with Map.from and emit that map. But that doesn’t trigger a rebuild. Any suggestions!

My freezed state is

onst factory RiskAttitudeState.loaded({
    required int customerId,
    required RiskAttitudeQuestionsInfo riskAttitude,
    required Map<String, List<int>> answerIds,
    @Default(FormzStatus.pure) FormzStatus status,
    int? finalRisk,
  }) = RiskAttitudeLoaded;

And I’m updating an integer in the list type List<int> in the map answerIds

Here is the bloc
Future _mapAnswerToState(

      String id, List<int> answerIds, Emitter<RiskAttitudeState> emit) async {

    await state.maybeMap(
      loaded: (RiskAttitudeLoaded loaded) async {
        if (loaded.answerIds.containsKey(id)) {
          loaded.answerIds.update(
            id,
            (_) => answerIds,
            ifAbsent: () {
              add(RiskAttitudeEvent.error(Exception('unknown Question ID: $id')));
              return answerIds;
            },
          );
        }

        emit(loaded.copyWith(answerIds: loaded.answerIds));
      },
      orElse: () async {},
    );
  }

For contest if I pass an empty map like this emit(loaded.copyWith(answerIds:{}));

the builder gets triggered.

2

Answers


  1. unfortunality i came accross this problem too. if your algorithm requires change one item of list maybe you can remove this item from your list and then change its properties. after that if you add the item to the list, builder will be triggered..

    Login or Signup to reply.
  2. I tried a small code with cubit and Equatable and it worked. the key note is that you should override props method and add answerIds and other fields if exists to props and all fields must be final.

    also notice to use Map<String, List<int>>.from to fill the map.

    so the state class looks like this:

    class UcHandleState extends Equatable {
      final Map<String, List<int>> answerIds;
      const UcHandleState({
        required this.answerIds,
      });
    
      @override
      List<Object> get props => [
            answerIds,
          ];
    
      UcHandleState copyWith({
        Map<String, List<int>>? answerIds,
      }) {
        return UcHandleState(
          answerIds: answerIds != null
              ? Map<String, List<int>>.from(answerIds)
              : this.answerIds,
        );
      }
    }
    

    and a simple cubit class for managing events is like below. in valueChanged I’m just passing List<int>.

    class TestCubit extends Cubit<TestState> {
      TestCubit() : super(const TestState(answerIds: {'1': [1, 1]}));
    
      void valueChanged(List<int> newValues ) {
        Map<String, List<int>> test = Map<String, List<int>>.from(state.answerIds);
        test['1'] = newValues;
        emit(state.copyWith(
          answerIds: test,
        ));
      }
    }
    

    so in UI I call valueChanged() method of cubit:

     cubit.valueChanged(newValues:[ Random().nextInt(50), Random().nextInt(70)]);
    

    and the blocBuilder gets triggered:

       return BlocBuilder<UcHandleCubit, UcHandleState>(
            buildWhen: (prev, cur) =>
            prev.answerIds!= cur.answerIds,
            builder: (context, state) {
              print(state.answerIds.values);
             ....
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search