am following this Bloc's official example and I couldn't find a way how to access the state without that if statement.

Let's have the example below, I would like to display a specific text based on the initial value of showText, the only possible solution to access the state is via: if(statement is ExampleInitial) {state.showText? return Text("yes") : return Text("no")}

But am finding this solution hard to implement when you have more values with initial values. Or am I doing this wrong?

////////// bloc
class ExampleBloc extends Bloc<ExampleEvent, ExampleState> {
  ExampleBloc() : super(const ExampleInitial()) {
    on<ExampleStarted>(_onExampleStarted);
  }

  void _onExampleStarted(ExampleStarted event, Emitter<ExampleState> emit) {
    emit(const ExampleInitial());
  }
}

////////// event
part of 'example_bloc.dart';

abstract class ExampleEvent extends Equatable {
  const ExampleEvent();
}

class ExampleStarted extends ExampleEvent {
  @override
  List<Object> get props => [];
}

////////// state
part of 'example_bloc.dart';

abstract class ExampleState extends Equatable {
  const ExampleState();
}

////////// state
class ExampleInitial extends ExampleState {
  final bool showText = false;

  const ExampleInitial();

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

// ui
class CreateExampleScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return BlocBuilder<ExampleBloc, ExampleState>(
        builder: (context, state) {
          return state.showText ? Text("yes") :Text("no"); // can't access to state.showText
      });
    }
}


Solution 1: Saurab Ghimire

You can declare a variable inside Bloc Class which will be global and need to be set inside the 'bloc.dart' file like in the case of Provider Package. This variable does not need state to be checked before accessing it in UI. You can access this value from the Navigation tree using context.

////////// bloc
class ExampleBloc extends Bloc<ExampleEvent, ExampleState> {
  ExampleBloc() : super(const ExampleInitial()) {
    on<ExampleStarted>(_onExampleStarted);
  }
  bool showText = false;
  void _onExampleStarted(ExampleStarted event, Emitter<ExampleState> emit) {
    emit(const ExampleInitial());
  }
}

// ui
class CreateExampleScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return BlocProvider.of<ExampleBloc>(context).showText
        ? const Text('Yes')
        : const Text('No');
  }
}

There is another way in which you declare abstract State Class to always have the boolean value. So, whatever new class extends those State will have inherited boolean value from parent class. This concept is called inheritance in OOP.

////////// state

abstract class ExampleState extends Equatable {
  const ExampleState();
  final bool showText = false;
}

////////// state
class ExampleInitial extends ExampleState {
  const ExampleInitial();
  // You can also set ExampleInitial to accept showText and send it to its 
  // parent class using 'super' method in constructor, 
  // if parent class has constructor with 'showText' as boolean
  @override
  List<Object> get props => [];
}  

// ui
class CreateExampleScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return BlocBuilder<ExampleBloc, ExampleState>(builder: (context, state) {
      return state.showText ? const Text("yes") : const Text("no");
    });
  }
}

A pragmatic usecase for different State Classes having different state variables is as follows:

Let's account for three states while fetching data from api

-if(state is DataLoadingState), // there is no need for state

-if(state is DataLoadedState) // state need to have a variable named weatherData containing temperatures, cities and so on.

-if(state is ErrorWhileLoadingState) // state needs to have a reason for the error. For example: errorMsg: 'Internal Server Error'

So, you need to check the state before accessing its values.