BehaviorSubject 订阅未侦听值更改

时间:2021-02-05 14:16:43

标签: angular axios angular-promise behaviorsubject subscriber

我正在创建一个有 API 服务的 Angular 应用程序。此服务使用 axios 调用 API 并根据需要更新 BehaviorSubject 的值,这里是该代码。

export const getStaticProps = async () => {
    let posts = []
    try 
    {
      // await the promise
      const querySnapshot = await firebase
        .firestore()
        .collection('posts')
        .orderBy('createdAt', 'desc')
        .get();
    
      // "then" part after the await
      querySnapshot.forEach(function (doc) {
        console.log(doc.data().title)
        console.log(doc.data().pid)
        posts.push({
          pid: doc.data().pid,
          title: doc.data().title,
        })
      })
      console.log(posts)
    } catch(error) {
        // catch part using try/catch
        console.log('Error getting documents: ', error)
        // return something else here, or an empty props, or throw an exception or whatever 
    }

    return {
        props: {
          posts
        }
    }
}

上述服务由home组件的构造函数调用。

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
    }

}

问题是,当响应来自 API 时,我收到 newsList,但没有检测到 startupList 的值发生变化。我在 tempStartup 上收到响应,这意味着 API 正在发送数据。
编辑 1
我有另一个名为 startup 的组件,其中我也订阅了 getStartupList()。当我切换到该组件并返回主组件时,startupList 会更新。这是切换到启动组件之前的日志。

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

切换到启动组件并返回主组件后登录。

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 []

P.S. getAllPost() 是从 app.component.ts 调用的,以便在创建应用程序后立即调用它。

1 个答案:

答案 0 :(得分:0)

push 到数组时,Angular 渲染器不知道列表已更新。对数组的底层引用没有改变,所以它不会重新渲染模板。

相反,您可以使用扩展运算符重新分配保存数组的变量。

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
        ...
      },
    );
  }
}
相关问题