New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Error NG0601 is reported incorrectly (triggered by NG0600) when calling toSignal inside a computed or effect #51027
Comments
It is really similar to #51055 - in the sense that it creates a new reactive node in a computed. As with #51082 - we could detect it earlier, see a WIP change: pkozlowski-opensource@bce5132 I think that we should take a step back and think about which reactive nodes creation is allowed in which reactive context. |
For now we've got, roughly, those types of reactive nodes and we should try to answer one question: does it make sense to create an instance of a given reactive node while another reactive node is an active consumer. Those are the options - for some of the combinations the answer is pretty straightforward - for others we could debate:
✅ - allow |
Minimal reproduction scenario: https://stackblitz.com/edit/stackblitz-starters-w46vxb |
This PR moves the Observable subscription of toSignal outside of the reactive context. As the result the toSignal calls are allowed in the computed, effect and all other reactive consumers. This is based on the reasoning that we already allow signals creation in a reactive context. Plus a similar change was done to the async pipe in the angular#50522 Fixes angular#51027
Looks great. I do hope people in general won't end up using But given that they will, makes me wonder if there should be a companion utility function to get the observable value one time. If people end up doing A utility function, something like In my 'journey' with nested computed I had to write my own safety checker (expecting #51082 to be imminent) and it actually saved me quite a few times. I found places where I was creating new nodes that wasn't immediately obvious. I'm guessing you decided not to put this behind a flag (?) but I feel like if there was one it could catch quite a few bugs. Also, this separate issue can now be marked as fixed: #50106 |
This PR moves the Observable subscription of toSignal outside of the reactive context. As the result the toSignal calls are allowed in the computed, effect and all other reactive consumers. This is based on the reasoning that we already allow signals creation in a reactive context. Plus a similar change was done to the async pipe in the angular#50522 Fixes angular#51027
This PR moves the Observable subscription of toSignal outside of the reactive context. As the result the toSignal calls are allowed in the computed, effect and all other reactive consumers. This is based on the reasoning that we already allow signals creation in a reactive context. Plus a similar change was done to the async pipe in the #50522 Fixes #51027 PR Close #51892
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
This PR moves the Observable subscription of toSignal outside of the reactive context. As the result the toSignal calls are allowed in the computed, effect and all other reactive consumers. This is based on the reasoning that we already allow signals creation in a reactive context. Plus a similar change was done to the async pipe in the angular#50522 Fixes angular#51027 PR Close angular#51831
Which @angular/* package(s) are the source of the bug?
core
Is this a regression?
No
Description
Before I begin I want to stress this issue is regarding confusing error reporting and not the signals implementation or design itself. The situation described below is most likely to be encountered when migrating from Observables to Signals, and can lead to confusion.
Sample Code
Here is a simple enough
computed
.It uses
toSignal
inside thecomputed
, but let's assume the user is new to Signals and doesn't know they shouldn't do that..Output
The above code reports two errors, the first of which is incorrect and misleading.
It turns out the first error is a side effect of the second error (despite being printed out first). If you only notice the first error (and personally I like to put breakpoints inside the vendor code where they are raised!) then you will be misled.
Explanation
Angular error NG0601 is triggered when an Observable does not emit synchronously when calling
toSignal
.This works internally by subscribing to the observable and checking immediately to see if the corresponding signal has been assigned a value.
angular/packages/core/rxjs-interop/src/to_signal.ts
Lines 179 to 184 in 25153e9
This sets a signal (which begins as
StateKind.NoValue
) to the synchronous value of the observable, which can then be checked ifrequireSync == true
.However since ALL writes to signals in
computed
andeffect
are forbidden this signal cannot be set, therefore it remains inStateKind.NoValue
state, thus triggering the erroneous message:Possible Solution
This could easily be solved by introducing a boolean to track the synchronous emission instead of relying on the state of the internal
toSignal
signal:The text was updated successfully, but these errors were encountered: