rx-angular: Missing change detection since `@rx-angular/cdk@1.0.0-beta.3`

Description

Since our Angular 14 update which included upgrading @rx-angular/cdk from 1.0.0-beta.2 to 1.0.0-beta.3 we got some problems with missing change detections.

We have an application with a splitted view with some *rxLet directives. With the update we encounter the problem, that changes triggered in the main view aren’t rendered in the sidebar, only after a clicking some UI element in the sidebar it gets rendered.

We found 2 options to fix the problem:

  1. Replace *rxLet="vm$; let vm" with *ngIf="vm$ | async as vm"
  2. Downgrading @rx-angular/cdk to 1.0.0-beta.2

Maybe it is related to the coalescing optimizations in the latest version.

Environment

Angular CLI: 14.1.1
Node: 16.13.2
OS: Windows 10

Angular: 14.1.1
Ivy Workspace: Yes

"@rx-angular/cdk": "1.0.0-beta.3",
"@rx-angular/state": "1.6.1",
"@rx-angular/template": "1.0.0-beta.33",

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 1
  • Comments: 25 (17 by maintainers)

Most upvoted comments

hey @twittwer invested a bit more time yesterday and now i’m pretty sure what is happening. Let me first say thank you for finding this, it was def. unexpected and looks like a bug in our scheduler implementation.

Let me try to explain what is going on here. Before https://github.com/rx-angular/rx-angular/commit/668c28ad0fb949666c58b27468188d759cfaf5c0 got merged, every single task executed in the scheduler queue was wrapped with NgZone#run, which led to performance issues as documented in the PR https://github.com/rx-angular/rx-angular/pull/946

The solution was to have a single NgZone#run executing all tasks in a scheduler tick. That way we reduced the amounts of NgZone calls and sideeffects coming from it.

pseudo code of the current scheduler flushWork fn:

performingWork = true;
NgZone.run(() => {
  while ( !hitDeadline && hasTask) {
     // run every task as long as we have time for it
     currentTask.execute();
   }
})
// => here the error occurs.
// After NgZone.run, NgZone executes code internally - without us knowing...
// the code can lead to other rxLet directives adding new tasks to the queue
// but, because `performingWork` is still true, the scheduler won't pick it up in the same tick and won't schedule a new
// tick
perfromingWork = false;

I will put together a PR with a fix for it 😃

Cool, your PR fixes the problem 🎉

@hoebbelsB How would you test a rx angular PR? Just build locally and npm link or is there any other way?

exequiel09 do I understand correctly this behavioral change is coming from angular 14, not from rx-angular

@hoebbelsB I’m using the latest versions of rx-angular with v13. When I upgraded to v14, rxLet / rxFor in some places don’t trigger initial render. When i switch back to v13, it works fine. I can try @twittwer findings to downgrade the cdk package and see if the same scenario happens when on v14 with downgraded cdk version.

It was probably this PR https://github.com/rx-angular/rx-angular/pull/946 introducing the changed behavior. Didn’t check 100%, but at least I know we’ve changed NgZone and scheduler behavior there.

Compared the flamecharts against each other and it looks like with beta.2 there was an additional NgZone call inside of the scheduler queue which is actually updating the DescriptionPanelComponentTemplate and is missing in beta.3. So the change should be visible somewhere in the scheduler implementation. Very interesting 😃

no-ngzone-tick

I stripped out NgRx & the Angular Router for a simpler reproduction scenario: https://github.com/twittwer/repro-rx-angular-1385

@hoebbelsB Now I can provide a ~minimal reproduction:
https://github.com/twittwer/repro-rx-angular-1385

After checkout the problem can be enabled/disabled by switching between the @rx-angular/cdk versions 1.0.0-beta.2 (without problem) and 1.0.0-beta.3 (with problem).

Thx for your quick response

I cannot promise but will try to reproduce it in a small environment