从父组件到子组件发送异步可观察数据

时间:2018-06-21 12:58:33

标签: angular

我正在尝试将异步数据(可观察的数据)从父级传递到子级组件,但是似乎更改未在子级组件上进行,我不确定为什么。

我有一个使用BehaviourSubject的(简体)服务:

@Injectable()
export class MyService {

  private _items: BehaviorSubject<any[]> = new BehaviorSubject([]);
  public items: Observable<any[]> = this._items.asObservable();

  list() {
    this.http.get('...').subscribe(items => {
      this._items.next(items);
    })
  }
}

(正在我的应用程序的其他位置定期调用list()函数来更新数据。)

然后我有了一个父组件:

@Component({
  selector: 'parent',
  templateUrl: '<child [items]="myService.items | async"></child>',
})
export class Parent {

  constructor(public myService: MyService) {
  }
}

和一个孩子:

@Component({
  selector: 'child',
  templateUrl: '<ul><li *ngFor="item of _items">{{item.name}}</li></ul>',
})
export class Parent implements OnChanges {

  @Input() items;
  _items = [];

  constructor() {
  }

  ngOnChanges(changes: SimpleChanges) {
    console.log('changes', changes);
    this._items = changes.items;
  }
}

我的理解是,使用async会自动订阅/取消订阅我的Observable,并将所有新数据传递给我的子组件。当有新数据输入时,我的子组件应该检测ngOnChanges中的那些更改并将其打印出来。

  1. 我的控制台输出从不触发,表明在子级中未检测到任何更改。我已经在我的父组件中手动订阅了Observable,以验证是否有新数据 传入,所以我不确定在这里哪里出错了。
  2. 在组件级别处理异步数据是否正确?

2 个答案:

答案 0 :(得分:2)

我可以建议您对代码进行一些更改:

父母:

@Component({
  selector: 'app-parent',
  changeDetection: ChangeDetectionStrategy.OnPush,
  templateUrl: '<app-child [items]="(myService.items | async)"></app-child>',
})
export class Parent {

  constructor(public myService: MyService) {
  }
}

-在[items]分配中添加了括号

孩子:

@Component({
  selector: 'app-child',
  changeDetection: ChangeDetectionStrategy.OnPush,
  templateUrl: '<ul><li *ngFor="item of _items">{{item.name}}</li></ul>',
})
export class Child implements OnChanges {

  @Input() items;
  _items = [];

  constructor() {
  }

  ngOnChanges(changes: SimpleChanges) {
    console.log('changes', changes);
    console.log(this.items);
    this._items = changes.items;
  }
}
  • 更改班级名称
  • 添加了changeDetection检测策略
  • 在应用程序的选择器前添加前缀也是一种很好的做法

答案 1 :(得分:2)

您快到了:-)。我只有几点提示...

@Injectable()
export class MyService {

  // Post-fixing your observable variables with `$` will make it easy to see them at the first glance.
  private _items$: BehaviorSubject<any[]> = new BehaviorSubject([]);
  get items$(): Observable<any[]> {
    // BehaviorSubject is an Observable as well
    return this._items$;
    // Or if you want to be safe and not leak your abstraction, use what you did...
    return this._items$.asObservable();
  }

  list() {
    // BehaviorSubject can subscribe itself
    this.http.get('...').subscribe(this._items$);
  }
}

我会将可观察值存储在您的父项字段中。如果您不需要该组件中其他任何地方的服务,为什么要保留引用。

@Component({
  selector: 'parent',
  templateUrl: '<child [items]="items$ | async"></child>',
})
export class ParentComponent {
  items$: Observable<any[]>;
  constructor(myService: MyService) {
    this.items$ = myService.items$;
  }
}

在这种情况下,您不需要ngOnChanges,因为您可以输入属性。如果不需要日志记录,则可以完全放弃访问器。

@Component({
  selector: 'child',
  templateUrl: '<ul><li *ngFor="item of items">{{item.name}}</li></ul>',
})
export class ChildComponent{

  private _items = [];

  @Input() set items(_items) {
    console.log('items', _items);
    this._items = _items;
  }
  get items() {
    return this._items;
  }
}

您的异步数据处理方法很好。在我看来,将关注点分离到'smart' and 'dumb' components中是可行的方法。

希望这会有所帮助:-)