【问题标题】:Async pipe does not fill new data from array异步管道不填充数组中的新数据
【发布时间】:2019-07-08 20:27:32
【问题描述】:

我的应用需要发出一些 api 请求(大约 500 个)并显示数据。它需要在请求完成时显示结果。到目前为止,我已将其设置为使用带有 observable 的异步管道。

我尝试将 ChangeDetectorRef.detectChanges() 放入 complete() 函数调用中。但视图没有受到任何影响。

news.component.ts

export class NewsComponent implements OnInit {

  news: Observable<News[]>;
  temp: News[] = new Array();

  constructor(private dataService: DataService, private ref: ChangeDetectorRef) {
  }

  ngOnInit() {
    this.news = this.getData();
  }

  getData(): Observable<News[]> {
    let newsArr = new Subject<News[]>();
    this.dataService.getTopNews().subscribe(val => {
      this.temp.push(val);
      newsArr.next(this.temp);
    }, null, () => {
      newsArr.complete();
      this.ref.detectChanges();
      console.log(this.news); //print all fetched data
    });
    return newsArr.asObservable();
  }
}

news.component.html

<app-news-item *ngFor="let newsItem of news | async" [news]="newsItem">
</app-news-item>

news-item.component.ts

@Component({
  selector: 'app-news-item',
  templateUrl: './news-item.component.html',
  styleUrls: ['./news-item.component.css']
})
export class NewsItemComponent implements OnInit {
  @Input() news: Subject<News>;
  constructor() { }

  ngOnInit() {
  }

}

视图 (html) 只更新一次,一开始只有一些数据块。数据正在正确加载,并且在获取所有数据后也会触发 complete()。

【问题讨论】:

  • 数据服务getTopNews函数有什么作用?
  • getTopNews 函数从远程获取所有数据并通过可观察对象一一返回。 ``` getTopNews(): Observable { // news = new Subject(); // forEach id 从远程获取数据 // news.next(Json data) // return news.asObservable(); } ````

标签: angular rxjs


【解决方案1】:

这不起作用的原因是它看起来像你正在将一个数组推送到你的临时数组中,所以它实际上是一个数组数组......你可以像修复它一样简单

this.temp.push(...val)

不过,我可能误解了 getTopNews 实际发出的内容(数组或单个新闻项)

但是,我建议尝试使用一些运算符来正确执行此操作,特别是累积数据的扫描运算符,因为我假设 getTopNews 发出多个“块”

import {scan} from 'rxjs/operators';

getData(): Observable<News[]> {
    return this.dataService.getTopNews().pipe(
      scan((acc, curr) => acc.concat(curr), []) // or acc.concat([curr]) if curr is actually a single news item and not an array
      // if you're not sure if its a single or array:
      // acc.concat(Array.isArray(curr) ? curr : [curr])
    );
  }
}

这是一个简单得多的结构,并且不需要临时变量或内部主题。如果您只希望它在全部完成后渲染,那么只需将 scan 替换为 reduce。

您的新闻项目组件中似乎也有一个错误,因为它似乎期望一个新闻项目主题而不是一个实际的新闻项目,这是基于其余代码得到的。

【讨论】:

  • 谢谢。为拙劣的逻辑道歉。
【解决方案2】:

由于您的应用发出近 500 个请求,并且您在所有请求完成后呈现数据,因此我建议采用更明确的方法,例如不使用异步管道。

export class NewsComponent implements OnInit, OnDestroy {
  private unsub: Subscription;
  news:News[] = [];

  constructor(private dataService: DataService) {}

  ngOnInit() {
    this.getData();
  }

  getData(): Observable<News[]> {
    const tmp: News[] = [];
    this.unsub = this.dataService.getTopNews().subscribe(val => {
      tmp.push(...val);
    }, null, () => {
      this.news = tmp;
      console.log(this.news); //print all fetched data
    });
  }

  ngOnDestroy() {
    this.unsub.unsubscribe();
  }
}

在你的模板中

<app-news-item *ngFor="let newsItem of news" [news]="newsItem"></app-news-item>

【讨论】:

  • 如果它渲染来自 500 个请求的数据,出于性能原因,您几乎肯定需要异步管道,因为您肯定需要推送更改检测。
【解决方案3】:

为什么要把事情复杂化?只需将服务中的 observable 放在组件上并使用异步管道订阅它,它将负责订阅和取消订阅..

export class NewsComponent implements OnInit {

  news = this.dataService.getTopNews();

  constructor(private dataService: DataService) {
  }
}

【讨论】:

    猜你喜欢
    • 2016-08-16
    • 2019-09-26
    • 2018-10-16
    • 1970-01-01
    • 1970-01-01
    • 2015-10-02
    • 2020-08-30
    • 1970-01-01
    • 2018-06-26
    相关资源
    最近更新 更多