【问题标题】:Component DOM not updating if data changes while viewing another component如果在查看另一个组件时数据发生更改,则组件 DOM 不会更新
【发布时间】:2019-07-03 15:06:21
【问题描述】:

我有一个应用程序,其中包含几个组件,每个组件都异步显示不同的数据。我正在使用 routerLink 在不同的组件之间导航。

问题是,如果我当前正在查看组件 B 时组件 A 中的数据发生更改,则当我返回组件 A 时,DOM 不会更新为新数据。(ngFor 列表将继续显示 test1、test2收到的数据。)但是,使用console.log,我可以在开发工具中看到,当我查看组件B时,组件A仍在接收数据。如果收到新数据时我在组件A中,则DOM 已更新,新数据正确显示。

我需要做些什么来确保在导航回组件时刷新 DOM?我想我可能会检测到 NavigationEnd 并将数据分配给它自己。有什么我遗漏的吗?

提前致谢,代码如下:

组件 A

import { Component, OnInit, ChangeDetectionStrategy, NgZone } from '@angular/core';
import { DataService } from '../../services/data.service';

@Component({
  selector: 'app-metars',
  templateUrl: './metars.component.html',
  styleUrls: ['./metars.component.scss'],
  changeDetection: ChangeDetectionStrategy.Default
})
export class TestComponent implements OnInit {

  public dataArray = ['test1', 'test2'];

  constructor(private _dataService: DataService, private zone: NgZone) { }

  ngOnInit() {
    this._dataService.data$
    .subscribe( data => {
        this.zone.run(() => {

          this.dataArray = data;
          console.log(data); // When in Component B, this is still firing in Dev Tools and I can see the new data being pushed.
        });
      }
    );
  }

}

组件 A HTML

<ul *ngFor="let data of dataArray">
    {{ data }}
</ul>
<br/>

数据服务

export class DataService {

  private data: string[] = new Array<string>();
  private _dataSource = new Subject<string[]>();

  data$ = this._dataSource.asObservable();


  constructor(public electronService: ElectronService) {

    this.intitalizeIPCs();
  }


  intitalizeIPCs() {

    this.electronService.ipcRenderer.on('receive-data', (event, arg) => {
      console.log('received data');
      this.data = arg;
      this._dataSource.next(this.data);
    });
  }

App.component.html

<app-nav></app-nav>
<div class="content">
    <router-outlet></router-outlet>
</div>

编辑 - 代码解决方案

接受的答案如下。正确的实现是通过使用异步管道。切换到异步管道后,我继续遇到一个问题,如果服务中的数据发生更改,组件在重新导航到它之前不会看到更改。通过将其封装在 NgZone 中解决了该问题。工作代码如下:

服务:

import { Injectable, NgZone } from '@angular/core';
import { ElectronService } from '../providers/electron.service';
import { Observable, BehaviorSubject } from 'rxjs';

@Injectable({
  providedIn: 'root'
})

export class DataService {

  private _data: BehaviorSubject<Array<string>> = new BehaviorSubject([]);
  public readonly data: Observable<Array<string>> = this._data.asObservable(); // Access this directly using async pipe.

  constructor(public electronService: ElectronService, private zone: NgZone) {

    this.intitalizeIPCs();
  }

  intitalizeIPCs() {
    this.electronService.ipcRenderer.on('receive-data', (event, arg) => {
      this.zone.run(() => {
        this._data.next( arg );
      });
    });
  }
}

组件:

import { Component, OnInit, ChangeDetectionStrategy } from '@angular/core';
import { DataService } from '../../services/metar.service';

@Component({
  selector: 'app-example',
  templateUrl: './example.component.html',
  styleUrls: ['./example.component.scss'],
  changeDetection: ChangeDetectionStrategy.Default
})
export class ExampleComponent implements OnInit {

  constructor(private _dataService: DataService) { }

  ngOnInit() {
  }


}

HTML

<ul *ngFor="let metar of _metarService.metars | async">
    {{ metar }}
</ul>

【问题讨论】:

    标签: angular rxjs electron


    【解决方案1】:

    我强烈建议使用async 管道而不是订阅流。您遇到的不是故障组件,而是内存泄漏。

    当您订阅 data$ 时,该订阅将保留在内存中,直到订阅被取消,您的情况永远不会发生这种情况。所以组件 A 的实例也需要保留在内存中。

    问题是改变到组件 B 的路由让 Angular 放弃了组件 A 的实例。所以 Angular 不再连接到它。从它的角度来看,该组件不再存在。当你将路由切换回组件 A 时,Angular 将创建一个新实例,它以['test1', 'test2'] 开头。

    【讨论】:

    • 我要去看看异步管道,谢谢。也就是说,如果我将 console.log 放入组件 A 的 ngOnInit 并切换回它,我看不到它出现。你确定它是在创建一个新实例还是我错过了什么?
    • @Kezz 如果组件由路由器管理,则创建一个新实例,是的。也许您发布帖子路由器配置以确保。
    • 这显然比我一直在阅读的内容要多,但我似乎无法弄清楚如何让它发挥作用。在 DataService 中更改 data$ 时,我的列表保持为空。我是否应该只在组件 A 中能够做到这一点:dataArray$: Observable&lt;string[]&gt; = this._dataService.data$&lt;ul *ngFor="let data of dataArray$ | async"&gt; {{ data}} &lt;/ul&gt;
    • @Kezz 绝对。但如前所述,这也是时间问题。如果组件在每次路由更改时创建,那么之前的值就会丢失。您可以通过将Subject() 替换为ReplaySubject(1) 来解决此问题。
    • 再次感谢您的帮助。我已经使用异步管道使用新代码编辑了我的问题。如果您发现任何问题,请告诉我。接受你的回答。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-05-01
    • 1970-01-01
    • 2020-05-14
    • 2018-01-15
    • 1970-01-01
    • 1970-01-01
    • 2020-08-22
    相关资源
    最近更新 更多