У меня есть служба в 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 - лучшее решение, поскольку это может быть большой объем данных, и он сильно меняется в процессе использования приложения.
Пожалуйста, взгляните на мой ответ. Возможно, это то, что вы ищете.





Сделайте это так:
Услуга
// 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 раза. Первый - с пустым списком, второй - с книгами.
хм интересно, я собираюсь протестировать это здесь. Но что делать, если книги не пустые, и они были обновлены, допустим, пользователь создал новую книгу. Будет ли изменение распространено на все подписанные компоненты?
собственно, после тестирования он отлично работает во всех случаях. Спасибо!
что бы вы хотели сделать, если нет книги? Потому что ваше условие if - это то, что вызывает цикл навсегда в случае пустых значений