Search code examples
flutterdartbloc

Flutter BLoC `buildWhen` property


I get a _CastError error at the last line of this piece of code

BlocBuilder buildUsernameField() {
  return BlocBuilder<ProfileBloc, ProfileState>(
    buildWhen: (previous, current) => previous != current && current is EditingUserInfo,
    builder: (context, state) => TextField(
      keyboardType: TextInputType.name,
      controller: TextEditingController(
          text: (state as EditingUserInfo).username.value),

saying that

I/flutter (26787): The following _CastError was thrown building BlocBuilder<ProfileBloc, ProfileState>(dirty, state:
I/flutter (26787): _BlocBuilderBaseState<ProfileBloc, ProfileState>#25b87):
I/flutter (26787): type 'Success' is not a subtype of type 'EditingUserInfo' in type cast

So what's happening is that it tries to build that widget when I am in another state (success). But in the buildWhen parameter, I specified that the widget should only build when the state is EditingUserInfo.

So as far as I understand, this error should not happen.

Here's my ProfileState :

part of 'profile_bloc.dart';

abstract class ProfileState extends Equatable {
  const ProfileState();
  
  @override
  List<Object> get props => [];
}

class ProfileInitial extends ProfileState {}

class EditingUserInfo extends ProfileState {
  final Username username;
  final Bio bio;
  final PhotoUrl photoUrl;
  final City city;
  final FormzStatus status;

  const EditingUserInfo({
    this.username = const Username.pure(),
    this.bio = const Bio.pure(),
    this.photoUrl = const PhotoUrl.pure(),
    this.city = const City.pure(),
    this.status = FormzStatus.pure,
  });

  EditingUserInfo copyWith({Username username, Bio bio, PhotoUrl photoUrl, City city, FormzStatus status}){
    return EditingUserInfo(
      username: username ?? this.username,
      bio: bio ?? this.bio,
      photoUrl: photoUrl ?? this.photoUrl,
      city: city ?? this.city,
      status: status ?? this.status,
    );
  }

  @override
  List<Object> get props => [username, bio, photoUrl, city];
}

class Loading extends ProfileState {}

class Error extends ProfileState {
  final String message;

  const Error({this.message});

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

class Success extends ProfileState {
  final String message;

  const Success({this.message});

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


Solution

  • You still have to check that the state variable is the proper state. The state is checked EVERY time it is changed, so the state variable can still be a different state, it just doesn't rebuild unless the buildWhen conditions are true.

    BlocBuilder buildUsernameField() {
    return BlocBuilder<ProfileBloc, ProfileState>(
    buildWhen: (previous, current) => previous != current && current is EditingUserInfo,
    builder: (context, state) {
     if(state is EditingUserInfo) {
      return TextField(
      keyboardType: TextInputType.name,
      controller: TextEditingController(
          text: state.username.info)
    }
    }