Home > Software design >  Flutter bloc is not rebuilding in 7.2.0 version with Equatable
Flutter bloc is not rebuilding in 7.2.0 version with Equatable

Time:10-20

I created simple app to test bloc 7.2.0 and faced that BlocBuilder doesn't rebuild after first successful rebuild. On every other trigger bloc emits new state, but BlocBuilder ignores it.

Please note, if I remove extends Equatable and its override from both, state and event, then BlocBuilder rebuilds UI every time Button pressed. Flutter version 2.5.1

If Equatable is necessary, why it's not working with it? If Equatable isn't necessary, why it's been used in initial creation via VSCode extension.

My code:

bloc part

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

//bloc
class MainBloc extends Bloc<MainEvent, MainState> {
  MainBloc() : super(MainInitial()) {
    on<MainButtonPressedEvent>(_onMainButtonPressedEvent);
  }

  void _onMainButtonPressedEvent(
      MainButtonPressedEvent event, Emitter<MainState> emit) {
    emit(MainCalculatedState(event.inputText));
  }
}

//states
abstract class MainState extends Equatable {
  const MainState();

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

class MainInitial extends MainState {}

class MainCalculatedState extends MainState {
  final String exportText;
  const MainCalculatedState(this.exportText);
}

//events
abstract class MainEvent extends Equatable {
  const MainEvent();

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

class MainButtonPressedEvent extends MainEvent {
  final String inputText;
  const MainButtonPressedEvent(this.inputText);
}

UI part

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

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: BlocProvider(
          create: (context) => MainBloc(),
          child: SubWidget(),
        ),
      ),
    );
  }
}

class SubWidget extends StatelessWidget {
  TextEditingController inputText = TextEditingController();
  String? exportText;

  @override
  Widget build(BuildContext context) {
    MainBloc mainBloc = BlocProvider.of<MainBloc>(context);

    return BlocBuilder<MainBloc, MainState>(
      builder: (context, state) {
        if (state is MainCalculatedState) {
          exportText = state.exportText;
        }
        return Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Text('${exportText ?? ''} data'),
              SizedBox(
                width: 200,
                child: TextField(
                  controller: inputText,
                ),
              ),
              ElevatedButton(
                  onPressed: () =>
                      mainBloc.add(MainButtonPressedEvent(inputText.text)),
                  child: const Text('Button')),
            ],
          ),
        );
      },
    );
  }
}

enter image description here

CodePudding user response:

Equatable is used to make it easy for you to program, how and when states are the same (no update) and when they are different (update).

Your updates do not work because you are sending the same state repeatedly, but you did not tell the Equatable extension how to find out if they are different. So they are all the same.

So to make sure your program understands that some states of the same kind are indeed different and should cause an update, you need to make sure you mention what makes them different:

class MainCalculatedState extends MainState {
  final String exportText;
  const MainCalculatedState(this.exportText);

  // this tells the Equatable base class to consider your text property
  // when trying to figure out if two states are different.
  // If the text is the same, the states are the same, so no update
  // If the text is different, the states are different, so it will update 
  @override
  List<Object> get props => [this.exportText];
}

If you remove Equatable altogether, two newly instanciated states are never equal, so that would solve your problem as well... except that at some point you will want them to be, and then you need to add it back in.

CodePudding user response:

Your MainCalculatedState needs to override the props getter from Equatable and return the list of all properties which should be used to assess equality. In your case it should return [exportText]. Example:

class MainCalculatedState extends MainState {
  final String exportText;
  const MainCalculatedState(this.exportText);

  @override
  List<Object> get props => [exportText];
}
  • Related