Состояние флаттера не обновляется после выхода нового состояния

Я использую bloc в приложении flutter, и моя проблема в том, что представление не обновляется при выходе нового состояния. Я хочу добавить новое сообщение в свой список сообщений. и я получаю то же состояние с новыми данными, но мое представление не обновляется после добавления нового сообщения в список. Блок:

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);
  }
}

мероприятие:

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

штат:

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];
}

и просмотр:

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),
            );
          },
        ),
      ),
    );
  }
}

Когда я добавляю новое сообщение, вид не обновляется. В чем моя ошибка.


person BeHappy    schedule 21.04.2020    source источник


Ответы (2)


Изменить: в конце концов оказывается, что вы используете equatable, и потому что, когда вы генерируете новое состояние, вы только изменяете список старого состояния, вставляя в него сообщение, а затем генерируя старое. state с тем же списком, поэтому, когда bloc сравнивает два состояния, и поскольку класс состояний расширяется equatable, блок считает их одинаковыми и не генерирует состояние

решение: удалите равноправный

or

используйте неизменяемые списки, чтобы вы могли создать новое состояние, которое имеет свойство, отличное от предыдущего, и может быть выделено блоком

person Haidar Mehsen    schedule 21.04.2020
comment
Итак, мне нужно удалить const в моем классе состояния? - person BeHappy; 22.04.2020
comment
вы можете оставить его, если вызываете его откуда-то еще (в чем я сомневаюсь), но в любом случае из mapEventToState () вы не должны вызывать его, особенно с использованием equatable, поэтому добавление неконстантного конструктора должно решить вашу проблему, см. ссылку в ответе - person Haidar Mehsen; 22.04.2020
comment
Я не хочу уступать другое государство. - person BeHappy; 22.04.2020
comment
вы пытались удалить конструкторы const, и это не сработало? извините, но я не могу попробовать это для вас, так как у меня нет вашего кода - person Haidar Mehsen; 22.04.2020
comment
Я определяю так DataLoaded({this.chatMessages}); - person BeHappy; 22.04.2020
comment
а также без Equatable работает. Но как с этим работать? - person BeHappy; 22.04.2020
comment
Я не понимаю, что вы сделали, и не понимаю, сработало это или нет (язык непонятен) - person Haidar Mehsen; 22.04.2020
comment
Я не понимаю, что вы имеете в виду под неконстантным конструктором, я просто меняю const DataLoaded({this.chatMessages}); на DataLoaded({this.chatMessages}); - person BeHappy; 22.04.2020
comment
то, что вы сделали, это то, что я имею в виду, вы возвращали тот же экземпляр состояния в блок, поэтому он не отправлял его - person Haidar Mehsen; 22.04.2020
comment
@BeHappy, посмотрите stackoverflow.com/q/21744677/9142279 - person Haidar Mehsen; 22.04.2020
comment
Это изменение не решает проблему. удаление Equatable работает. - person BeHappy; 22.04.2020
comment
ах, хорошо, но рассуждения все те же, блок считал следующее состояние таким же, как и предыдущее, потому что вы каждый раз возвращаете один и тот же список сообщений и используете equatable (который, в свою очередь, будет отмечать два состояния как равные, когда они сравниваются, потому что вы не используете неизменяемые списки, но сохраняете тот же список и просто вставляете в него) - person Haidar Mehsen; 22.04.2020
comment
Я слежу за списком дел в документации блока. Думаю, у нас такой же подход, но для меня это не работает. - person BeHappy; 22.04.2020

Список чего-то не работает с Equatable. Он всегда возвращает истину, даже если элементы списка не совпадают.

Так что у меня есть обходной путь. Я добавил еще одно свойство List и свойство bool, чтобы помочь людям, у которых много свойств в 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;
}

Надеюсь вам поможет, у меня работает :)

person akaymu    schedule 30.06.2021