angular - BehaviorSubject 订阅未侦听值更改
问题描述
我正在创建一个有 API 服务的 Angular 应用程序。该服务使用 axios 调用 API 并根据需要更新 BehaviorSubject 的值,这是其代码。
import { Injectable } from "@angular/core";
import axios, { AxiosInstance } from 'axios';
import { BehaviorSubject, Observable, Subject } from "rxjs";
import { Post } from "../mock/post.model";
@Injectable({
providedIn: 'root',
})
export class APIService {
private AxiosInstance = axios.create();
private newsList: BehaviorSubject<Post[]>;
private startupList: BehaviorSubject<Post[]>;
private allPosts: Post[];
constructor() {
this.initBS();
}
initBS() {
this.newsList = new BehaviorSubject<Post[]>(null);
this.startupList = new BehaviorSubject<Post[]>(null);
}
getAllPosts(): void {
this.AxiosInstance.get(MY_API_ENDPOINT)
.then(data => {
const resp: Post[] = this.mapNews(data.data);
this.allPosts = resp;
let tempNews: Post[] = [];
let tempStartup: Post[] = [];
for (const post of this.allPosts) {
for (const cat of post.category) {
if (cat.toLocaleLowerCase().includes('news')) {
tempNews.push(post);
}
if (cat.toLocaleLowerCase().includes('startup')) {
tempStartup.push(post);
}
}
}
this.newsList.next(tempNews);
this.startupList.next(tempStartup);
})
.catch(error => {
console.error(error);
});
}
getNewsList() {
return this.newsList.asObservable();
}
getStartupList() {
return this.startupList.asObservable();
}
mapNews(data: any[]): Post[] {
return MAPPED_RESPONSE_TO_POST_ARRAY; // logic to convert axios response to Post array
}
}
上述服务是由 home 组件的构造函数调用的。
import { Component, ViewEncapsulation } from '@angular/core';
import { Post } from '../../@core/mock/post.model';
import { APIService } from '../../@core/services/API.service';
@Component({
selector: 'ngx-editors',
encapsulation: ViewEncapsulation.None,
styleUrls: ['./home.component.scss'],
templateUrl: './home.component.html',
})
export class HomeComponent {
newsList: Post[];
startupList: Post[];
constructor(private api: APIService) {
this.newsList = [];
this.startupList = [];
let i = 0;
api.getNewsList().subscribe(
(value) => {
console.log('onHomeNews:');
console.log(value);
console.log(this.startupList);
if (value != null) {
for (const post of value) {
if (i < 4) {
this.newsList.push(post);
i++;
}
}
}
},
(error) => {
console.log(error);
},
() => {
console.log('onComplete:');
});
i = 0;
api.getStartupList().subscribe(
(value) => {
console.log('onHomeStartup:');
console.log(value);
console.log(this.startupList);
for (const post of value) {
if (i < 4) {
this.startupList.push(post);
i++;
}
}
},
(error) => {
console.log(error);
},
() => {
console.log('onComplete:');
});
}
}
问题是当响应来自 API 但没有检测到启动列表的值更改时,我正在获取新闻列表。我在 tempStartup 上收到响应,这意味着 API 正在发送数据。
编辑 1
我有另一个名为启动的组件,我也订阅了 getStartupList()。当我切换到该组件并返回主组件时,startupList 会更新。这是切换到启动组件之前的日志。
sub-header.component.ts:86 home
home.component.ts:40 onHomeNews:
home.component.ts:41 null
home.component.ts:42 []
home.component.ts:62 onHomeStartup:
home.component.ts:63 null
home.component.ts:64 []
home.component.ts:40 onHomeNews:
home.component.ts:41 (8) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]
home.component.ts:42 []
切换到启动组件并返回主组件后的日志。
sub-header.component.ts:86 home
home.component.ts:40 onHomeNews:
home.component.ts:41 null
home.component.ts:42 []
home.component.ts:62 onHomeStartup:
home.component.ts:63 null
home.component.ts:64 []
home.component.ts:40 onHomeNews:
home.component.ts:41 (8) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]
home.component.ts:42 []
sub-header.component.ts:86 startup
sub-header.component.ts:86 home
home.component.ts:40 onHomeNews:
home.component.ts:41 (8) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]
home.component.ts:42 []
home.component.ts:62 onHomeStartup:
home.component.ts:63 (5) [{…}, {…}, {…}, {…}, {…}]
home.component.ts:64 []
PS getAllPost() 从 app.component.ts 调用,以便在创建应用程序后立即调用它。
解决方案
Angular 渲染器不知道列表何时更新push
到数组。对数组的底层引用没有改变,所以它不会重新渲染模板。
相反,您可以使用扩展运算符重新分配保存数组的变量。
export class HomeComponent {
...
constructor(private api: APIService) {
this.newsList = [];
this.startupList = [];
let i = 0;
api.getNewsList().subscribe(
(value) => {
...
this.newList = [...this.newsList, post]; // <-- reassign using spread operator
...
},
...
);
i = 0;
api.getStartupList().subscribe(
...
this.startupList = [...this.startupList, post]; // <-- reassign using spread operator
...
},
);
}
}
推荐阅读
- bash - 检查一个文件的每个 ip 是否存在于另一个文件中,然后采取行动
- flutter - 用户输入URL地址时如何在flutter中传递参数(使用auto_route)
- android - Firebase DB:应用程序打开了太多文件。一个进程中可用文件描述符的最大值默认为 1024
- java - 如何在不启动 AVD 的情况下在 Windows Android Studio 上使用 tensorflow lite + kotlin?
- reactjs - 我正在尝试验证“多个”输入字段。我找不到任何方法来验证选择字段?
- python - python - 如何使用pyinstaller将python复制到exe而忽略模块/依赖项?
- c - 需要使代码高效并降低时间复杂度
- database - 如何在颤振中将飞镖对象插入到 sqflite 中的单列表中?
- reactjs - 使用 Recharts 制作坐标平面
- reactjs - Next Build 永远挂起