简体   繁体   中英

flutter_bloc many Event to many BlocBuilder

Recently I am learning flutter_bloc , and I refer to the project flutter_weather .

What I am puzzled is that if a Bloc class has many Events, and most of the Event s will have values returned by State , and there are many BlocBuilder s in the project, what should I do if I want a BlocBuilder to only respond to a certain Event ?

The method I can think of is to divide this Bloc into multiple Bloc s, or treat each value to be returned as an attribute of Bloc , BlocBuilder uses the buildwhen method to determine whether to rebuild.

But both of these methods are not good for me. Is there any good method? It is best to have projects on github for reference.

For example: This is Event:

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

class WeatherRequested extends WeatherEvent {
  final String city;

  const WeatherRequested({@required this.city}) : assert(city != null);

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

class WeatherRefreshRequested extends WeatherEvent {
  final String city;

  const WeatherRefreshRequested({@required this.city}) : assert(city != null);

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

This is State:

abstract class WeatherState extends Equatable {
  const WeatherState();

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

class WeatherInitial extends WeatherState {}

class WeatherLoadInProgress extends WeatherState {}

class WeatherLoadSuccess extends WeatherState {
  final Weather weather;

  const WeatherLoadSuccess({@required this.weather}) : assert(weather != null);

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

class WeatherLoadFailure extends WeatherState {}

This is Bloc:

class WeatherBloc extends Bloc<WeatherEvent, WeatherState> {
  final WeatherRepository weatherRepository;

  WeatherBloc({@required this.weatherRepository})
      : assert(weatherRepository != null),
        super(WeatherInitial());

  @override
  Stream<WeatherState> mapEventToState(WeatherEvent event) async* {
    if (event is WeatherRequested) {
      yield* _mapWeatherRequestedToState(event);
    } else if (event is WeatherRefreshRequested) {
      yield* _mapWeatherRefreshRequestedToState(event);
    }
  }

  Stream<WeatherState> _mapWeatherRequestedToState(
    WeatherRequested event,
  ) async* {
    yield WeatherLoadInProgress();
    try {
      final Weather weather = await weatherRepository.getWeather(event.city);
      yield WeatherLoadSuccess(weather: weather);
    } catch (_) {
      yield WeatherLoadFailure();
    }
  }

  Stream<WeatherState> _mapWeatherRefreshRequestedToState(
    WeatherRefreshRequested event,
  ) async* {
    try {
      final Weather weather = await weatherRepository.getWeather(event.city);
      yield WeatherLoadSuccess(weather: weather);
    } catch (_) {}
  }
}

This is BlocConsumer:

// BlocBuilder1
BlocBuilder<WeatherBloc, WeatherState>(
  builder: (context, state) {
    if (state is WeatherLoadInProgress) {
      return Center(child: CircularProgressIndicator());
    }
    if (state is WeatherLoadSuccess) {
      final weather = state.weather;
      return Center(child: Text("WeatherRequested "))
    }
)
// BlocBuilder2
BlocBuilder<WeatherBloc, WeatherState>(
  builder: (context, state) {
    if (state is WeatherLoadInProgress) {
      return Center(child: CircularProgressIndicator());
    }
    if (state is WeatherLoadSuccess) {
      final weather = state.weather;
      return Center(child: Text("WeatherRefreshRequested"))
    }
)

The problem is that I want BlocBuilder1 only to work when the type of Event is WeatherRequested and BlocBuilder2 only works when the type of Event is WeatherRefreshRequested. One of my ideas is that each Event has its own State, and then judge the type of State in buildwhen.

Is there any good method?

if you want to build you widget to respond for certain states you should use BlocConsumer and tell that bloc in buildWhen to tell it what state it should build/rebuild you widget on.

BlocConsumer<QuizBloc, QuizState>(
  buildWhen: (previous, current) {
    if (current is QuizPoints)
      return true;
    else
      return false;
  },
  listener: (context, state) {},
  builder: (context, state) {
    if (state is QuizPoints)
      return Container(
        child: Center(
          child: Countup(
            begin: 0,
            end: state.points,
            duration: Duration(seconds: 2),
            separator: ',',
          ),
        ),
      );
    else
      return Container();
  },
);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM