Flutter: блок не удаляет данные из списка

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

Моя блочная логика,

class FavouriteBloc extends Bloc<FavouriteEvent, List<Articles>> {
  FavouriteBloc() : super(null);
  List<Articles> articles = [];
  @override
  Stream<List<Articles>> mapEventToState(FavouriteEvent event) async* {
    switch (event.eventType) {
      case EventType.add:
         articles.add(event.articles);
         yield articles;
        break;
      case EventType.delete:
        articles.remove(event.articles);
        yield articles;
        break;
    }
  }
}

класс события,

enum EventType {add, delete}

class FavouriteEvent{
  Articles articles;
  EventType eventType;
  FavouriteEvent.add({this.articles,this.eventType});
  FavouriteEvent.remove({this.articles,this.eventType});
}

часть пользовательского интерфейса,

На этом экране, когда я добавляю в избранное, отображается список добавленных мной карточек, а затем я использую onTap, чтобы удалить их из списка, но этого не происходит.

class FavouriteScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    var height = MediaQuery.of(context).size.height;
    var width = MediaQuery.of(context).size.width;
    return Scaffold(
      appBar: AppBar(),
      body: BlocBuilder<FavouriteBloc, List<Articles>>(
        buildWhen: (previous, current) {
          if(previous.length<current.length){
            return true;
          }
          return false;

        },
        builder: (context, newsList) {
          if (newsList == null) {
            return Center(
              child: Text(
                week7.Strings.noFav,
                style: Theme.of(context).textTheme.headline6,
              ),
            );
          }
          return ListView.builder(
              itemCount: newsList.length,
              shrinkWrap: true,
              itemBuilder: (context, index) {
                return GestureDetector(
                  onTap: () { 
                    BlocProvider.of<FavouriteBloc>(context).add(  //<--- this is how I'm trying to remove
                        FavouriteEvent.remove(
                            articles: Articles(
                                urlToImage: newsList[index].urlToImage,
                                title: newsList[index].title,
                                author: newsList[index].author
                            ),
                            eventType: EventType.delete));
                  },
                  child: Card(...),
                );
              });
        },
      ),
    );
  }
}

класс модели,

@JsonSerializable()
class Articles {
  Source source;
  String author;
  String title;
  String description;
  String url;
  String urlToImage;
  DateTime publishedAt;
  String content;
  Articles({
    this.source,
    this.author,
    this.title,
    this.description,
    this.url,
    this.urlToImage,
    this.publishedAt,
    this.content,
  });

  factory Articles.fromJson(Map<String, dynamic> json) =>
      _$ArticlesFromJson(json);
}

Так может ли кто-нибудь сказать мне, что я здесь делаю не так?


person Pokaboom    schedule 03.03.2021    source источник
comment
эй, можешь поделиться классом модели?   -  person gowthaman C    schedule 03.03.2021
comment
@gowthamanC хорошо, я добавил свой модельный класс в вопрос   -  person Pokaboom    schedule 03.03.2021


Ответы (1)


Дарт сравнивает, являются ли два объекта одним и тем же экземпляром. Вам необходимо переопределить оператор == или использовать такую ​​библиотеку, как equatable.

Первое, что вам нужно сделать, это удалить buildWhen. Сейчас он будет обновляться (перестраиваться) только при добавлении элементов, но не при их удалении.

        buildWhen: (previous, current) {
          if(previous.length<current.length){
            return true;
          }
          return false;

        },

Используйте класс State для представления состояния, потому что список всегда один и тот же, и он не будет перестраиваться. После этого настройте код виджета для использования state.articles.

class FavouriteState {
 final List<Articles> articles;
 FavouriteState(this.artticles);
}

class FavouriteBloc extends Bloc<FavouriteEvent, FavouriteState> {
  FavouriteBloc() : super(null);
  List<Articles> _articles = [];
  @override
  Stream<FavouriteState> mapEventToState(FavouriteEvent event) async* {
    switch (event.eventType) {
      case EventType.add:
         _articles.add(event.articles);
         yield FavouriteState(_articles);
        break;
      case EventType.delete:
        _articles.remove(event.articles);
        yield FavouriteState(_articles);
        break;
    }
  }
}

Пример сравнения urlToImage, title и author

@JsonSerializable()
class Articles {
  Source source;
  String author;
  String title;
  String description;
  String url;
  String urlToImage;
  DateTime publishedAt;
  String content;
  Articles({
    this.source,
    this.author,
    this.title,
    this.description,
    this.url,
    this.urlToImage,
    this.publishedAt,
    this.content,
  });

    @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is Articles && runtimeType == other.runtimeType && urlToImage == other.urlToImage &&
      title == other.title && author == other.author;

  @override
  int get hashCode => urlToImage.hashCode ^ title.hashCode ^ author.hashCode;

  factory Articles.fromJson(Map<String, dynamic> json) =>
      _$ArticlesFromJson(json);
}

Пример использования пакета Equatable

@JsonSerializable()
class Articles  extends Equatable{
  Source source;
  String author;
  String title;
  String description;
  String url;
  String urlToImage;
  DateTime publishedAt;
  String content;
  Articles({
    this.source,
    this.author,
    this.title,
    this.description,
    this.url,
    this.urlToImage,
    this.publishedAt,
    this.content,
  });

 @override
  List<Object> get props => [author, title, description, url, urlToImage, content];

  factory Articles.fromJson(Map<String, dynamic> json) =>
      _$ArticlesFromJson(json);
}
person YoBo    schedule 03.03.2021
comment
хорошо, это работает, но он восстанавливается после изменения состояния, так что мое состояние в buildWhen правильное или мне нужно сделать что-то еще - person Pokaboom; 03.03.2021
comment
Перестройка нормальна при изменении состояния. Ваше состояние - когда размер списка меняется, перестраивать. Добавление или удаление элементов из списка вызовет перестройку, и это нормальное поведение. Если он не перестроится, вы не увидите измененные статьи. - person YoBo; 03.03.2021
comment
tbh нужно удалить buildWhen. Вы хотите, чтобы перестройка запускалась каждый раз, когда вы добавляете или удаляете элемент из списка. Нет смысла в таком состоянии. Сейчас он будет перестраиваться только при добавлении элементов, а не при их удалении. - person YoBo; 03.03.2021
comment
извините, я забыл "нет", он не восстанавливается - person Pokaboom; 03.03.2021
comment
Если вы удалите элемент, он не будет восстановлен. Верно? Это исходит от buildWhen. Удалите buildWhen и все будет хорошо. - person YoBo; 03.03.2021
comment
нет, он все еще не восстанавливается - person Pokaboom; 03.03.2021
comment
Вы можете разделить государственный класс - person gowthaman C; 03.03.2021
comment
Это потому, что вы используете Список ‹Статьей› в качестве состояния. попробуйте следующее в BLoC: yield articles.toList(); для добавления и удаления, чтобы создать новый список. Блок не будет перестраиваться, если предыдущее состояние совпадает с новым. - person YoBo; 03.03.2021
comment
хорошо, ты очень полезен - person Pokaboom; 03.03.2021
comment
Обновил мой код примером того, как создать состояние, содержащее articles. Предлагаю вам двигаться в этом направлении. - person YoBo; 03.03.2021