Как сохранить наблюдаемые данные из API с помощью rxJS в Angular 5?

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

Итак, я пошел дальше и попытался использовать BehaviorSubjects для хранения данных. Я хорошо поработал, используя это так:

Услуга:

books = new BehaviorSubject<Book[]>(null);
setBooks(book: Book[]) {
    this.books.next(book);
}
getBooks() {
    this.http.get(...).do(
        (res) => {
            this.setBooks(res.books);
        }
    );
}

Составные части:

ngOnInit() {
    this.booksService.books.subscribe(
        (books) => {
            // in case the api was never called
            if (books == null) {
                return this.booksService.getBooks().subscribe();
            }
            console.info(books);
            // ...
        }
    );
}

Он отлично работает, когда есть книги, но если книги представляют собой пустой массив (что является одним из ожидаемых вариантов поведения), программа застревает в цикле, вызывая API навсегда. Тестируя его, я решил, что он застревает в части .do () в вызове службы, но я не понимаю, почему.

Я читал, что здесь BehaviorSubject не предназначен для использования с нулевым начальным значением, но, как и предложил @estus, при использовании ReplaySubject (1) происходит то же самое.

Интересно, есть ли «правильный» способ хранить такие данные. Я также не думаю, что использование localstorage - лучшее решение, поскольку это может быть большой объем данных, и он сильно меняется в процессе использования приложения.

что бы вы хотели сделать, если нет книги? Потому что ваше условие if - это то, что вызывает цикл навсегда в случае пустых значений

edkeveked 09.06.2018 23:30

Пожалуйста, взгляните на мой ответ. Возможно, это то, что вы ищете.

Lynx 242 09.06.2018 23:51
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Angular и React для вашего проекта веб-разработки?
Angular и React для вашего проекта веб-разработки?
Когда дело доходит до веб-разработки, выбор правильного front-end фреймворка имеет решающее значение. Angular и React - два самых популярных...
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Мы провели Twitter Space, обсудив несколько проблем, связанных с последними дополнениями в Angular. Также прошла Angular Tiny Conf с 25 докладами.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
Мое недавнее углубление в Angular
Мое недавнее углубление в Angular
Недавно я провел некоторое время, изучая фреймворк Angular, и я хотел поделиться своим опытом со всеми вами. Как человек, который любит глубоко...
Освоение Observables и Subjects в Rxjs:
Освоение Observables и Subjects в Rxjs:
Давайте начнем с основ и постепенно перейдем к более продвинутым концепциям в RxJS в Angular
0
2
1 760
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Сделайте это так:

Услуга

// init books as BehaviorSubject with an empty array of type Book
books = new BehaviorSubject<Book[]>([]);

setBooks(book: Book[]) {
     this.books.next(book);
}

 // return books as an Observable
 getBooks(): Observable<Book[]> {
     // only if length of array is 0, load from server
     if (this.books.getValue().length === 0) {
          this.loadBooks();
     }

     // return books for subscription even if the array is yet empty. 
     // It‘ll get filled soon.
     return this.books.asObservable();  
  }  

  private loadBooks(): void {
      this.http.get(...).do(
         (res) => {
             this.books.next(res.books);
       } );
  }

TS-файл

ngOnInit() {
    this.booksService.getBooks().subscribe(
        (books) => {  
            console.info('books: ', books);
        });
}

Здесь происходит то, что вы загружаете список книг только один раз. Подписка на книги устанавливается, и как только список книг поступает, новый список распространяется среди всех подписчиков.

Таким образом, вы должны увидеть журнал консоли 2 раза. Первый - с пустым списком, второй - с книгами.

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

Gabriel Bitencourt 10.06.2018 02:32

собственно, после тестирования он отлично работает во всех случаях. Спасибо!

Gabriel Bitencourt 10.06.2018 05:57

Другие вопросы по теме