Reputation: 3988
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
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
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