BeHappy
BeHappy

Reputation: 3988

Flutter state not update after yield new state

I am using bloc in flutter app and my problem is view is not update when yield new state. I want to add new message to my list of messages. and I yield same state with new data but my view doesn't update after adding new message to list. Bloc:

class ChatBloc extends Bloc<ChatEvent, ChatState> {
  @override
  ChatState get initialState => ChatInitial();

  @override
  Stream<ChatState> mapEventToState(ChatEvent event) async* {
   if (event is AddToMessages) {
      yield* _mapAddToMessagesEventToState(event.chatMessage);
    }
  }

  Stream<ChatState> _mapAddToMessagesEventToState(ChatMessage chatMessage) async* {
    List<ChatMessage> chatMessages = (state as DataLoaded).chatMessages;
    chatMessages.insert(0, chatMessage);
    yield DataLoaded(chatMessages: chatMessages);
  }
}

event:

abstract class ChatEvent extends Equatable {}
class AddToMessages extends ChatEvent {
  final ChatMessage chatMessage;
  AddToMessages({@required this.chatMessage});
  @override
  List<Object> get props => [chatMessage];
}

state:

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

class ChatInitial extends ChatState {
  const ChatInitial();

  @override
  List<Object> get props => [];
}
class DataLoaded extends ChatState {
  final List<ChatMessage> chatMessages;
  const DataLoaded({this.chatMessages});

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

and View:

class ChatScreen extends StatelessWidget {
  Widget createBody(ChatState state, BuildContext context) {
    if (state is DataLoaded) {
      return Column(
        children: <Widget>[
          MessagesList(
            messages: state.chatMessages,
          ),
          SendBar(
            onMessage: (message) => BlocProvider.of<ChatBloc>(context).add(
              AddToMessages(
                chatMessage: ChatMessage(
                  chatMessageType: ChatMessageType.TEXT,
                  dateTime: DateTime.now(),
                  message: message,
                  userId: store.state.userProfile.id,
                ),
              ),
            ),
          ),
        ],
      );
    } else {
      return Container();
    }
  }

  @override
  Widget build(BuildContext context) {
    return BlocProvider<ChatBloc>(
      create: (context) {
        return ChatBloc(chatRepository: chatRepository)..add(DataLoaded(chatMessages: []));
      },
      child: BlocListener<ChatBloc, ChatState>(
        listener: (context, state) async {},
        child: BlocBuilder<ChatBloc, ChatState>(
          builder: (context, state) {
            return Scaffold(
              body: createBody(state, context),
            );
          },
        ),
      ),
    );
  }
}

When I add new message, view doesn't update. Where is my mistake.

Upvotes: 5

Views: 2432

Answers (2)

akaymu
akaymu

Reputation: 31

List of something is not working properly with Equatable. It always returns true even if List elements are not same.

So I have a workaround for this. I added another List property and a bool property to help people who has lots of properties in State of Bloc.

class DataLoaded extends ChatState {
  final List<Member> roomMembers;
  final List<ChatMessage> chatMessages;
  final bool isOpen;

  
  final List<Object> allElements;

  DataLoaded({this.chatMessages, this.roomMembers, this.isOpen}) 
    : allElements = [...chatMessages, ...roomMembers, isOpen];

  @override
  List<Object> get props => allElements;
}

I hope it will help you, it works on me :)

Upvotes: 0

HII
HII

Reputation: 4109

Edit: turns out after all that because you are using equatable, and because when you emit a new state, you are only changing the list of the old state by inserting a message into it, then emitting the old state with the same list,so when bloc compares the two states, and because the state class extends equatable, the bloc considers them the same and doesn't emit a state

solution: remove the equatable

or

use immutable lists so you can emit a new state that has a different property than the previous one and can be distinguished by bloc

Upvotes: 5

Related Questions