Bloc: Question: How to change bloc state without event?

Created on 24 Sep 2019  路  3Comments  路  Source: felangel/bloc

For example, I have bloc which should periodically check for new messages:

import 'dart:async';

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

@immutable
class Message extends Equatable {
  final String text;
  Message(this.text) : super([text]);
}

abstract class MessageRepository {
  Future<List<Message>> checkForNewMessages();
}


@immutable
abstract class MessageEvent extends Equatable {
  const MessageEvent([List props = const <dynamic>[]]) : super(props);
}

abstract class MessageState extends Equatable {
  const MessageState([List props = const <dynamic>[]]) : super(props);
}
class InitialMessageState extends MessageState {}
class NewMessageState extends MessageState {
  final Message message;
  NewMessageState(this.message) : super([message]);
}


class MessageBloc extends Bloc<MessageEvent, MessageState>  {
  final MessageRepository _repository;
  @override
  MessageState get initialState => InitialMessageState();
  Timer _pollTimer;

  MessageBloc(this._repository){
    _pollTimer = Timer.periodic(Duration(seconds: 60), (_)=>_pollForMessage);
  }

  @override
  void dispose() {
    _pollTimer.cancel();
    super.dispose();
  }

  void _pollForMessage() async {
    (await _repository.checkForNewMessages()).forEach((message){
      var newMessageState = NewMessageState(message);
      ////////////////////////////////////////////////
      /////  how to add this state to bloc state? ////
      ////////////////////////////////////////////////
    });
  }
}

I have only one idea with the internal private event:

class _ProcessNewMessage extends MessageEvent {
  final Message message;
  _ProcessNewMessage(this.message) : super([message]);
}

class MessageBloc extends Bloc<MessageEvent, MessageState>  {
  ...
  Stream<MessageState> mapEventToState(MessageEvent event) async* {
    if (event is _ProcessNewMessage) {
      yield NewMessageState(event.message);
    }
  }

  void _pollForMessage() async {
    (await _repository.checkForNewMessages()).forEach((message){
      dispatch(_ProcessNewMessage(message));
    });
  }
  ...
}

So, is it good way or not?

P.S. Of cause this can be other type of the bloc, for example, websocket bloc, which connects to the Serber and just wait for new messages without polling.

question

Most helpful comment

Thank you!

All 3 comments

no, states should only get changed through events.
create an event that takes your message, then dispatch it.
then in mapEventToState respond to this event by changing the repository and yielding a new state.

Hi @Hacker-CB 馃憢
Thanks for opening an issue!

As @bigworld12 mentioned, anytime you want to trigger a state change you must dispatch an event. As a result, you can poll or listen (if you use Streams) for messages and then dispatch a MessageReceived event which contains the message as a property.

You might want to check out the flutter timer tutorial for inspiration since that tutorial shows how to hook a bloc up to a stream of incoming data.

Hope that helps 馃憤

Thank you!

Was this page helpful?
0 / 5 - 0 ratings