简体   繁体   中英

How to debug RxJS / Angular? View not updating when new value is emitted

I'm really banging my head against the wall with this one... :-\

I have a dumb component that with an @Input() that receives an array:

export class ChildComponent implements OnChanges {

  @Input() items: Item[];

  ngOnChanges(changes: SimpleChanges) {
    console.log('ngOnChanges fired:', changes['items'].currentValue.length)
  }
}

The parent component passes the array to the child component via a template binding and the async pipe:

<h1>Parent Component</h1>

<child [items]="items$ | async"></child>

My understanding is that changes should automatically be detected when using the async pipe with @Input() allowing them to be processed within the ngOnChanges lifecycle hook.

Is this correct?

However, ngOnChanges is not fired in the child component when items$ emits a new value.

I have a DataStore class that maintains this observable array of items. As new items are fetched, it generates a new array (immutable) and pushes it through the items$ observable. However, the changes aren't detected in the child component. If I click around the page a bit, eventually change detection kicks in and it will update.

Here's the kicker: I created a sample of the problem on StackBlitz , only to find out it works fine there!!!!

So, I know there is something different my real code vs the simplified example, but I have not been able to track it down.

That is why my question is:

How to debug RxJS / Angular?

  • I've added logging to the items$ inside the parent component and I can see the new values arriving just fine, but the child component is not receiving them. I can see that ngOnChanges is not being fired within the child component.

  • I thought maybe the items$ observable reference was getting reassigned somewhere, leaving the template with a subscription to an observable that isn't actually getting new emissions, so I made the @Input() a getter/setter can I could monitor each time it was set, and it only occurs once.

  • I tried changing the child component to use the OnPush change detection strategy, but it had no effect.

I'm stumped...

Any suggestions on how I can track down my issue?

Thanks: :-)

Make sure the observable is emitting by putting {{ items$ | async | json }} {{ items$ | async | json }} {{ items$ | async | json }} in the parent component somewhere near the child. You will probably find that items$ is not emitting values, if it was then the child would get updated.

Are you modifying the current array and reemitting the same instance? When you modify the array make sure to construct a new array with the spread operator, map or filer rather than push and popping values then having the observable emit the same instance of an array with modified data. Make sure you emit a new instance of an array, don't mutate the old one.

Not related to your question but I tend to use setter properties over OnChanges

export class ChildComponent {
  items: Item[];
  @Input('items')
  set itemsSet(items: Item[]) {
    this.items = items;
    console.log('items set:', items.length);
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM