Thank you! Just a couple of days ago I stumbled upon the situation to set the value of a form from an input signal and came to the same conclusion: this is on of the circumstances where you have to use an effect. It's the bridge! I hope some day in the future there will be signal driven forms, where you can add a reactive source for its values...
You're welcome. I guess the day where ReactiveForms become Signals-compatible is nearer than we might think. The Angular team said second half of this year. Let's see what v19 brings along.
Another awesome video. I have watched all of your videos, and they have greatly improved my understanding of Signals as a whole. Thank you for constantly keeping the community up-to-date with NgNews and all of your awesome videos
very good video, one question what is the correct way to call the signal property from a computed signal in template ? I saw you had like "state().amount", but not "state().amount()" ?
In my example I used two-way binding. So state().amount works because I am passing the Signal itself. For "normal" property binding it would be as you said: state().amount().
I am using effect for reactive forms update (input as signal) and using it for viewChild(signal queries). I was facing an issue with ViewChild references (even in AfterViewInit). The viewChild was initially returning undefined because the element wasn’t defined when I tried to access it. To solve this, I utilized an effect that updates as soon as the host element is defined. Great videos! I'm always looking forward to watching all your videos.
Hey Zohaib, thanks, did you try to access the viewChild outside of a Reactive Context? So not within effect or the template? As you said AfterViewInit, I guess that this is the case. If you use the effect(), that's the right place. Btw, it could be that some things might change v19. I don't know the details but we all will hear it in a little bit more than a month.
@@RainerHahnekamp Yes, I did try accessing viewChild outside of the reactive context, specifically in response to a click event, and it worked in that scenario. However, using effect() was necessary for my use case, as I needed to update the element as soon as it was defined.
@@ZohaibAslam-fv9oc Yeah, I think some patterns have to change a little bit and we might require more utility function where effect and template as reactive context are not sufficient enough.
You're welcome. I hope I got the message through that effect() is perfectly ok as long as you remember the asynchronous part and use computed for dervied Signals. For the future, you can expect new wrapper functions coming up.
hi Rainer, first of all i'm absolutely thankful for your work on sharing knowledge about angular. I've read your comment about ~toObservable is just a wrapper on the effect~, but i'm just corious what do you think about an idea of fetching data based on signal, in the following way: 1. id is part of the state so im using a signal, eg. input signal 2. then i'm executing asychronous operation, so i'm using toObservable on id signal eg. toObservable(id).pipe(switchMap=>fetchData) 3. but the response should be part of the state so i'm using toSignal on the above observable I've found that way more intuitive for me at the beggining, when i've started working with signals api, but maybe there is something wrong with this concept, especially i've started wondering when i saw that you used untracked inside an effect. the disadvantage i'm finding about this aproach is readability of toSignal(toObservable(signal)), but in overall I think this is ok because it let me keep more reactive way of coding
Hi Jakub, you are very welcome. Yeah if you do signal -> observable -> signal because you need the power of RxJs, that's perfectly fine. In terms of readability you could write your own wrapper function or using an existing one. For example @ngrx/signals has an rxMethod which could help, but you would have to set the signal in a tap operator. Then you have the vast amount of utility functions at ngxtension.netlify.app/getting-started/introduction/. There you'll definitely find something. For the future, you will probably use the resource funcion which will land in Angular 19 as experimental (but I'd still use it right away)
for the future in angular, an effect could have an option to be async, which would solve this kind of bugs and make it easier for new users (hence making effects synchronous by default). Gread Video and explanation Rainer! Danke!
There has been some talk - since the arrival of Signals - that it should be possible to configure the scheduler of the effect. Maybe one day one could come up with a synchronous scheduler...we'll see. Gern geschehen!
A very balanced and informative take on effect. Recently, a PR from Alex Rickabaugh was merged that would alter the execution timing of effect. There is gonna be a difference between execution timing between 'component' effect and 'root' effect. Not to mention, a new afterRenderEffect hook was recently introduced. Honest I don't fully understand everything, just hope for more docs/examples by then 😅
Yeah, the question is how much it will have an impact on simple tasks like fetching data or form synchronization. When it comes to using effect for DOM manipulation - I guess - it might be a different thing. We'll see. Angular 19 will soon be released.
Great work, explanations and walkthroughs, as always; thank you. It's much appreciated! Quick one though: say, you are using NgRx signal store for state management and a particular piece of state (e.g. product), has attributes that should be used to get other pieces of state (usually API calls, but via the signal store which effectively triggers signal writes in state) - would using an effect to do the 'side effect' updates to state be advisable? For example, the product has a catalogueId, brandId, etc and the intention is to load the product's catalogue and brand alongside the product itself, say within a product-detail component... What would be the best approach here?
Well, in this case the SignalStore would expose a method created via rxMethod. The component passes the Signal to that method and the SignalStore does the rest. You don't have to call the effect, the SignalStore will do it for you internally.
@RainerHahnekamp hmm, that's an interesting approach to it. Had never thought of it that way. Lemme see if I can refactor an implementation and see how that goes. Thanks so much! 🙏
@@lordememphis Yeah, so as I said in the video. If you have experience with RxJs and you see effect as subscribe you will always try to "not subscribe" and "connect" signals together. With rxMethod you connecting on the surface, but internally it is calling the effect.
@@RainerHahnekamp this is really insightful, thanks! I gave it a go and it worked like a charm. These APIs are pretty powerful! Initially, I thought I had to be explicit about the 'exact' type for signals and observables, but I later observed it does that internally and all I worry about is the actual data. Had to go through the docs for it to stick as well. As always, thank you so much for the insight and assistance!
Thanks, this has certainly cleared up some things regarding the use of effects. What's your opinion on mimicking the Rxjs 'take(1)' with effects by calling the '.destroy()' function of the effect inside its content at the end? Would you say this is a valid use or something to avoid?
Generally speaking, I don't see this as a valid use case? Why do you want to manually destroy an effect? It has auto-destroy built-in. Whenever you call effect(), the effect internally access the DestroyRef of the current Injection Context. That means, if you are inside a component and it gets destroyed, so does the effect. Careful though, if you are in a Service provided in root. In that case, your effect will run the whole application lifetime unless you destroy it or provide an alternative injector.
@@RainerHahnekamp It was mainly a thought in case you, for whatever reason, needed to run a side effect only once. In that case, given your answer, it would probably be better to find a different solution
@@giigiigdasm I wouldn't put it like you have to find another solution. You need to see the effect as an implicit unsubscribe that is right in most cases. For example: Angular 16 introduced takeUntilDestroyed. You put it to the type and it the unsubscription that we have now with the effect's destruction.
I agree that effects can and should be used if you know what you are doing of course. Thanks for the great video. I think it's like useEffect in react.
@@RainerHahnekamp yes, React does not know signals. I meant use cases are similar. Both are used for synchronization. And Solidjs also has createEffect, which is for side effects. Would like to hear your thoughts about emerging signal patterns in Angular in future videos like redux like pattern for state management. Thank you.
Hi, so I did actually a lot of videos on state management. In particular on the global NgRx store which uses Redux and the SignalStore. Did you check them out and is there something you find missing there?
@@RainerHahnekamp no, those videos are great. I saw some redux like patterns with just service and signals from other content creators here without libraries. We don't use state management libraries at the moment in the project, so I was interested. I think we will start using signalStore soon, I really like it.
@@giorgipaikidze85 I see. You can also do without a library and write it on your own but given its central role in an application, I'd feel better if a battle-tested library does the job.
Yeah, I had it already in my other video. There is one "disappointment" though. I still have to finish a video which I recorded in April. That one will come with the light mode (only exception - big promise)
Great video! It's the first video of your that I've seen apart from the 100 sec summaries, that Ive been following for a while. One small question: are you using any kind of plugin for showing those http fancy requests on the console?
Ah, you mean ng-news? Yeah there is separate channel for that, but this one here is my personal one. There is no fancy extension. I just wrote an interceptor that logs the requests in a nice way :). That's it.
at 18:00 tallking about use case of effect during data fatching i saw another video where where Ben Lesh, RxJS Team Lead talking about not to use effect to make async staf, like fetching data from API. what do you say about it?
Yes, I’ve seen that. He’s referring to a use case where using an effect doesn’t make sense. In his example, he has an event listener that fetches data. But in modern Angular, we’re working more and more with Signals, like the one coming from the input function. In cases like these, you can’t really avoid using an effect. His argument is, “Look, I got by without an effect here, so you never need one.” That’s like me stepping outside on a sunny day and saying, “I didn’t need an umbrella today, so I’ll never need one.” You get where I’m going with this metaphor? There are definitely many cases where you don’t need an effect, and we’ll likely see more functions in the future that internally handle it. But if an effect is the only option in a scenario, then it’s the right tool to use. I have a huge amount of respect for Ben, but still, in case of doubt, you should listen more to what Alex Rickabaugh says. He doesn’t just understand Signals-he knows exactly how they’re integrated into Angular and the broader impact they have on the framework. Does that make sense?
@@RainerHahnekamp I just wanted to take a moment to thank you for explaining things to me so clearly. Your guidance made a real difference, and I truly appreciate your help.
@@YanLoonG13 Good to hear and you're welcome :). Btw, my comment above is public. So in case you have a discussion with somebody else, you can quote me ;)
@@RainerHahnekamp One question related to the same topic. Why don't you use the computed signal over the customer signal to achieve the same fetch call instead of effect? Thanks. Excellent content as always!!
@@elyoaprogrammer If I use computed to request data via an asynchronous task, then I'd completely go against the intention of a computed. You see, a computed should generate a new Signal whenever a dependent Signal (or multiple ones) changes. With an asynchronous that computed would return something like Signal. I'd say that is way more unreadable than the effect. On top of that, you don't gain anything with computed in that case. In this video I show the danger of the effect when you would have a synchronous change to another Signal. But in this case it is asynchronous. So effect doesn't do any harm. Why would you go for a computed here?
Thanks for making this video. I am still finding the way which I wanted to solve my problem. Problem is: I am using NGRX signal store. Where I am calling http call and storing the response in variable and now api may take 10-20 sec to fetch the data and my component is loaded, now i want to have the data which i got from api response and based on that data I need to do further things in my component. Here I am using effect ? Is it correct way or how to avoid this??
If you are using the Signal Store you have more options available. In your case that would be the rxMethod. It is an abstraction to the effect, meaning it still uses it internally. There are some videos from me about the SignalStore.
Great video 👍 In the example with the observable where you subscribe to it in the constructor. If you only work with observables there, you don't have to unsubscribe the subscribe.
You use "untracked" for updateing. What is the main difference between usage of "untracked" and "allowSignalWrites"? Because it seems that both option make more or less the same.
If you wrap a Signal access in untracked(), that Signal will not be tracked. allowSignalWrites allows you - as untracked - to set Signals but it would start tracking those Signals as well. There is a better explanation at github.com/angular/angular/issues/56155
Thanks for the informative video. I use the effect to download and change the language in the application. But I use the effect in the constructor(). Is this correct? constructor() { effect(() => { this.setTrans().then(); }); } async setTrans(): Promise { switch (this.lang()) { case Lng.en: await import('../translate/en').then(f => {this.trs.set(f.trans)}); break; case Lng.uk: await import('../translate/uk').then(f => {this.trs.set(f.trans)}); break; } this.setHeader(); }
Technically it is correct. You can shorten this.setTrans().then() to just this.setTrans(). Promises are not like Observables. You are tracking the lang() here. I would track the Signals directly in the effect for better readability and use an untracked. So it could look like this: constructor() { effect(() => { const lang = this.lang(); untracked(() => this.setTrans(lang)) }); } async setTrans(lang: string): Promise { switch (lang) { case Lng.en: await import('../translate/en').then(f => {this.trs.set(f.trans)}); break; case Lng.uk: await import('../translate/uk').then(f => {this.trs.set(f.trans)}); break; } this.setHeader(); }
At 30:00, how can i initialize the state if the page gets loaded? Lets say we need the amount to be 1 if the page gets loaded AND if the productId changes?
No, try to avoid ngOnInit in this case. If I want to get the value of a Signal I try to use it in an effect or the template. There I don't have any issues, with Signals that aren't ready yet.
@@RainerHahnekamp What if the selectedProductId is an input() ? I have this case at my code now where i dont know when to load the entity. In ngOnInit or via effect or via computed?
@@Heskmark Do you see a problem when you use the effect()? It is the last use case that I've showed. Makes perfectly sense. With ngOnInit you have the problem that it is one-timer. So if the id changes, you don't get informed. computed is not made for that use case.
Isn't use case 3 an example of propagation of state changes? I see a difference here using toObservable and then piping it to a switchMap to get the customer compared to the effect usage: the signals change is done in the observable subscription, and not inside of the effect.. I'm not sure of how toObservable works under the hood, though
If at all, Use Case 3 is "ASYNCHRONOUS" propagation fo state changes. If it helps you can also say effect doesn't change a Signal it all, it just calls an asynchronous method and then it stops. Once that task we are very far away from the "juristication of an effect".
I don't see the usage of async is future proof. We know that Signal Components will come and then everything should be a signal in the template. Btw. toObservable is a wrapper for effect.
for valid effect use cases ... shouldn't we use rxMethod? I mean in most use cases... I think rxMethod is very powerful! You don't need "untracked" then.
In your edit-customer component, you mention that the foobar computed needs to be called in the template in a reactive context in order for the computed run. Why don't you define your customer signal as the computed instead?
@@RainerHahnekamp Ah yes, that is true! I cannot think of a way of avoiding the returned computed from being a promise. The only way I can think of avoiding using an effect is something nested like this. This of course relies rxjs and rxjs interop, and doesn't look nice either! @Injectable() class ManfredService { doAsyncThing(value: number) { return new Promise(resolve => { setTimeout(() => resolve(value * 5), 1000); }); } } @Component({ standalone: true, template: `{{ myComputed() }}`, changeDetection: ChangeDetectionStrategy.OnPush, providers: [ManfredService], }) export class ManfredComponent { myInput = input.required(); manfredService = inject(ManfredService); myComputed = toSignal( toObservable(this.myInput).pipe(switchMap(value => from(this.manfredService.doAsyncThing(value)))), ); }
@@RainerHahnekamp Sorry I had a response with a code snippet but must not have clicked 'reply'. I can't avoid returning a promise in the computed, you are right! I was however able to avoid using an effect by a mixture of rxjs and rxjs interop. something like: myNewSignal = toSignal(toObservable(myInput).pipe(switchMap((value) => from(myService.returnPromise(value))))) I think using an effect is definitely cleaner and requires less imports
@@seanclarke-1 If you say you can live without the switchMap, then definitely effect. If you say switchMap is important, then I'd do a manual subscription to the Observable and set the effect in its next callback.
Yes, but I think a solution for these kind of reset patterns are even more important. At the moment, it is not very readable to do with it computed. Support for asynchronous tasks will probably go hand in hand with the future of the HttpClient (speaking of optional RxJS).
36:31 readonly state = computed(() => { return { product_id : this.selectedProductID(), amount : signal(1) }; } ) Also for reactive forms I would suggest not to use effects but events if you need to react on state-changes ... effects have only a very very slim use-case like for an example triggering toasts, sending telemetry or logging ... what you did in this video is kinda forcing effects into scenarios in which other options are better e.g. using stores, child-components or events but the worst thing you did is coming up with this "more readable" nonsense .. purely subjective and if you really think about it also not true in the slightest because you have to deal with asynchronous code
I’ve provided some examples so we can focus on practical scenarios rather than debating abstract concepts. It would be great if you could pick one of the examples and show how you think it should be approached. I’m eager to have a serious discussion and see what you have in mind, but refrain from using words like ‘nonsense.’
@@RainerHahnekamp sure .. 18:40 instead of updating the customer signal with set you could just define the customer signal as computed of id .. this in fact would be more readable because you don't have to jump up and down to understand what's going on and it would be declarative
@@mjdev-i1p The only way how I see is: customer = computed(() => this.customerService.byId(id)) That computed will in this case return a Signal. You could probably call the Signal in the template and use the async pipe (should work with Promises). I am not sure if a Signal holding a Promise is a better solution but the actual problem will be, that you cannot have any consumers (other computeds) on that customer anymore. Because the Signal has no clue that a Promise can resolve, etc. I've read an article describing a concept of an asynchronous Signal, but that would require that the framework also knows how to deal with it. How would your approach look like?
@@RainerHahnekamp well it depends on what you try to achieve ... if you just need to consume the signal at this one instance then the approach as you described it would be completely fine ... however if you need to share the value between multiple consumers then I would use a signal-store The only scenario in which i see an effect as the preferable solution is if you want to do a quick and dirty patch to something
@@mjdev-i1p Yes, so the use case was here for a single component. If the Signals gets accessed by multiple components, then I would expose it to a Service or would directly go with the SignalStore and I would pass the Signal to that service. But also here, a self-written service or the rxMethod of the SignalStore will use the effect for you. So you delegate it. Small note: Having an effect in a service providedIn: root is always a little bit problematic. Because it runs over the whole application lifecycle and you might have to come up with manual destruction.
Thank you! Just a couple of days ago I stumbled upon the situation to set the value of a form from an input signal and came to the same conclusion: this is on of the circumstances where you have to use an effect. It's the bridge!
I hope some day in the future there will be signal driven forms, where you can add a reactive source for its values...
You're welcome. I guess the day where ReactiveForms become Signals-compatible is nearer than we might think. The Angular team said second half of this year. Let's see what v19 brings along.
Another awesome video. I have watched all of your videos, and they have greatly improved my understanding of Signals as a whole. Thank you for constantly keeping the community up-to-date with NgNews and all of your awesome videos
Thanks Dhaval! Happy to hear (as always)
Kudos Rainer! You are the best!
Thanks
Really good Video. I will it recommend to my colleagues
Hey, thanks!
very good video, one question what is the correct way to call the signal property from a computed signal in template ? I saw you had like "state().amount", but not "state().amount()" ?
In my example I used two-way binding. So state().amount works because I am passing the Signal itself. For "normal" property binding it would be as you said: state().amount().
I am using effect for reactive forms update (input as signal) and using it for viewChild(signal queries). I was facing an issue with ViewChild references (even in AfterViewInit). The viewChild was initially returning undefined because the element wasn’t defined when I tried to access it. To solve this, I utilized an effect that updates as soon as the host element is defined.
Great videos! I'm always looking forward to watching all your videos.
Hey Zohaib, thanks, did you try to access the viewChild outside of a Reactive Context? So not within effect or the template? As you said AfterViewInit, I guess that this is the case.
If you use the effect(), that's the right place. Btw, it could be that some things might change v19. I don't know the details but we all will hear it in a little bit more than a month.
@@RainerHahnekamp Yes, I did try accessing viewChild outside of the reactive context, specifically in response to a click event, and it worked in that scenario.
However, using effect() was necessary for my use case, as I needed to update the element as soon as it was defined.
@@ZohaibAslam-fv9oc Yeah, I think some patterns have to change a little bit and we might require more utility function where effect and template as reactive context are not sufficient enough.
Thanks a lot for that content. This helps me lot! A missing part for me was also to use untracked, which was a missing peace for me.
You're welcome. I hope I got the message through that effect() is perfectly ok as long as you remember the asynchronous part and use computed for dervied Signals. For the future, you can expect new wrapper functions coming up.
@@RainerHahnekamp Yes , message was clear :-) I will also communicate this Video to my colleges, very usefull. 🙂
hi Rainer, first of all i'm absolutely thankful for your work on sharing knowledge about angular.
I've read your comment about ~toObservable is just a wrapper on the effect~, but i'm just corious what do you think about an idea of fetching data based on signal, in the following way:
1. id is part of the state so im using a signal, eg. input signal
2. then i'm executing asychronous operation, so i'm using toObservable on id signal eg. toObservable(id).pipe(switchMap=>fetchData)
3. but the response should be part of the state so i'm using toSignal on the above observable
I've found that way more intuitive for me at the beggining, when i've started working with signals api, but maybe there is something wrong with this concept, especially i've started wondering when i saw that you used untracked inside an effect.
the disadvantage i'm finding about this aproach is readability of toSignal(toObservable(signal)), but in overall I think this is ok because it let me keep more reactive way of coding
Hi Jakub, you are very welcome.
Yeah if you do signal -> observable -> signal because you need the power of RxJs, that's perfectly fine.
In terms of readability you could write your own wrapper function or using an existing one. For example @ngrx/signals has an rxMethod which could help, but you would have to set the signal in a tap operator. Then you have the vast amount of utility functions at ngxtension.netlify.app/getting-started/introduction/. There you'll definitely find something.
For the future, you will probably use the resource funcion which will land in Angular 19 as experimental (but I'd still use it right away)
for the future in angular, an effect could have an option to be async, which would solve this kind of bugs and make it easier for new users (hence making effects synchronous by default). Gread Video and explanation Rainer! Danke!
There has been some talk - since the arrival of Signals - that it should be possible to configure the scheduler of the effect. Maybe one day one could come up with a synchronous scheduler...we'll see. Gern geschehen!
A very balanced and informative take on effect.
Recently, a PR from Alex Rickabaugh was merged that would alter the execution timing of effect. There is gonna be a difference between execution timing between 'component' effect and 'root' effect.
Not to mention, a new afterRenderEffect hook was recently introduced.
Honest I don't fully understand everything, just hope for more docs/examples by then 😅
Yeah, the question is how much it will have an impact on simple tasks like fetching data or form synchronization. When it comes to using effect for DOM manipulation - I guess - it might be a different thing. We'll see. Angular 19 will soon be released.
Great video, thanks for sharing.
Sure thing!
Great work, explanations and walkthroughs, as always; thank you. It's much appreciated!
Quick one though: say, you are using NgRx signal store for state management and a particular piece of state (e.g. product), has attributes that should be used to get other pieces of state (usually API calls, but via the signal store which effectively triggers signal writes in state) - would using an effect to do the 'side effect' updates to state be advisable? For example, the product has a catalogueId, brandId, etc and the intention is to load the product's catalogue and brand alongside the product itself, say within a product-detail component... What would be the best approach here?
Well, in this case the SignalStore would expose a method created via rxMethod. The component passes the Signal to that method and the SignalStore does the rest.
You don't have to call the effect, the SignalStore will do it for you internally.
@RainerHahnekamp hmm, that's an interesting approach to it. Had never thought of it that way. Lemme see if I can refactor an implementation and see how that goes. Thanks so much! 🙏
@@lordememphis Yeah, so as I said in the video. If you have experience with RxJs and you see effect as subscribe you will always try to "not subscribe" and "connect" signals together. With rxMethod you connecting on the surface, but internally it is calling the effect.
@@RainerHahnekamp this is really insightful, thanks! I gave it a go and it worked like a charm. These APIs are pretty powerful! Initially, I thought I had to be explicit about the 'exact' type for signals and observables, but I later observed it does that internally and all I worry about is the actual data. Had to go through the docs for it to stick as well.
As always, thank you so much for the insight and assistance!
@@lordememphis Thanks, I will pass on the compliments.
Thanks, this has certainly cleared up some things regarding the use of effects. What's your opinion on mimicking the Rxjs 'take(1)' with effects by calling the '.destroy()' function of the effect inside its content at the end? Would you say this is a valid use or something to avoid?
Generally speaking, I don't see this as a valid use case? Why do you want to manually destroy an effect? It has auto-destroy built-in. Whenever you call effect(), the effect internally access the DestroyRef of the current Injection Context. That means, if you are inside a component and it gets destroyed, so does the effect. Careful though, if you are in a Service provided in root. In that case, your effect will run the whole application lifetime unless you destroy it or provide an alternative injector.
@@RainerHahnekamp It was mainly a thought in case you, for whatever reason, needed to run a side effect only once. In that case, given your answer, it would probably be better to find a different solution
@@giigiigdasm I wouldn't put it like you have to find another solution. You need to see the effect as an implicit unsubscribe that is right in most cases.
For example: Angular 16 introduced takeUntilDestroyed. You put it to the type and it the unsubscription that we have now with the effect's destruction.
Very much appreciated, thank you! Subscribed 👍
Great, thanks!
Great example, thank you
Hey, thanks a lot.
I agree that effects can and should be used if you know what you are doing of course. Thanks for the great video. I think it's like useEffect in react.
You are welcome. I think useEffect and effect do have a lot of differences. The major one is definitely that React doesn't know Signals.
@@RainerHahnekamp yes, React does not know signals. I meant use cases are similar. Both are used for synchronization. And Solidjs also has createEffect, which is for side effects. Would like to hear your thoughts about emerging signal patterns in Angular in future videos like redux like pattern for state management. Thank you.
Hi, so I did actually a lot of videos on state management. In particular on the global NgRx store which uses Redux and the SignalStore. Did you check them out and is there something you find missing there?
@@RainerHahnekamp no, those videos are great. I saw some redux like patterns with just service and signals from other content creators here without libraries. We don't use state management libraries at the moment in the project, so I was interested. I think we will start using signalStore soon, I really like it.
@@giorgipaikidze85 I see. You can also do without a library and write it on your own but given its central role in an application, I'd feel better if a battle-tested library does the job.
finally, the dark mode is here! :D Thanks for Video!
Yeah, I had it already in my other video. There is one "disappointment" though. I still have to finish a video which I recorded in April. That one will come with the light mode (only exception - big promise)
@@RainerHahnekamp I think we'll definitely forgive you that :D
Great video! It's the first video of your that I've seen apart from the 100 sec summaries, that Ive been following for a while.
One small question: are you using any kind of plugin for showing those http fancy requests on the console?
Ah, you mean ng-news? Yeah there is separate channel for that, but this one here is my personal one. There is no fancy extension. I just wrote an interceptor that logs the requests in a nice way :). That's it.
@@RainerHahnekamp Yes! Ng-news 😄 The interceptor was my obvious answer, but just in case ☺️
Great explanation
Thank you!
at 18:00 tallking about use case of effect during data fatching
i saw another video where where Ben Lesh, RxJS Team Lead talking about not to use effect to make async staf, like fetching data from API.
what do you say about it?
Yes, I’ve seen that. He’s referring to a use case where using an effect doesn’t make sense. In his example, he has an event listener that fetches data. But in modern Angular, we’re working more and more with Signals, like the one coming from the input function. In cases like these, you can’t really avoid using an effect. His argument is, “Look, I got by without an effect here, so you never need one.” That’s like me stepping outside on a sunny day and saying, “I didn’t need an umbrella today, so I’ll never need one.” You get where I’m going with this metaphor?
There are definitely many cases where you don’t need an effect, and we’ll likely see more functions in the future that internally handle it. But if an effect is the only option in a scenario, then it’s the right tool to use.
I have a huge amount of respect for Ben, but still, in case of doubt, you should listen more to what Alex Rickabaugh says. He doesn’t just understand Signals-he knows exactly how they’re integrated into Angular and the broader impact they have on the framework.
Does that make sense?
@@RainerHahnekamp I just wanted to take a moment to thank you for explaining things to me so clearly. Your guidance made a real difference, and I truly appreciate your help.
@@YanLoonG13 Good to hear and you're welcome :). Btw, my comment above is public. So in case you have a discussion with somebody else, you can quote me ;)
@@RainerHahnekamp One question related to the same topic. Why don't you use the computed signal over the customer signal to achieve the same fetch call instead of effect? Thanks. Excellent content as always!!
@@elyoaprogrammer If I use computed to request data via an asynchronous task, then I'd completely go against the intention of a computed.
You see, a computed should generate a new Signal whenever a dependent Signal (or multiple ones) changes.
With an asynchronous that computed would return something like Signal. I'd say that is way more unreadable than the effect.
On top of that, you don't gain anything with computed in that case. In this video I show the danger of the effect when you would have a synchronous change to another Signal. But in this case it is asynchronous. So effect doesn't do any harm.
Why would you go for a computed here?
Another great video.
Thanks, link is now active
Thanks for making this video.
I am still finding the way which I wanted to solve my problem.
Problem is: I am using NGRX signal store. Where I am calling http call and storing the response in variable and now api may take 10-20 sec to fetch the data and my component is loaded, now i want to have the data which i got from api response and based on that data I need to do further things in my component. Here I am using effect ? Is it correct way or how to avoid this??
If you are using the Signal Store you have more options available. In your case that would be the rxMethod. It is an abstraction to the effect, meaning it still uses it internally. There are some videos from me about the SignalStore.
@@RainerHahnekamp i am using rxMethod, I will try to create a stackblitz over the weekend and will share the exact issue with you.
Great video 👍 In the example with the observable where you subscribe to it in the constructor. If you only work with observables there, you don't have to unsubscribe the subscribe.
Thanks, why don't you see the need for a manual unsubscription, if you have an existing subscripton?
@@RainerHahnekamp I mean if you use async pipe then you have the automatic unsubscribe and if not then you have to unsubscribe manually
@@n1hkrc Ah yes, yes. I thought it is related that I do it in the constructor. All good!
You use "untracked" for updateing. What is the main difference between usage of "untracked" and "allowSignalWrites"? Because it seems that both option make more or less the same.
If you wrap a Signal access in untracked(), that Signal will not be tracked. allowSignalWrites allows you - as untracked - to set Signals but it would start tracking those Signals as well.
There is a better explanation at github.com/angular/angular/issues/56155
Thanks for the informative video.
I use the effect to download and change the language in the application.
But I use the effect in the constructor(). Is this correct?
constructor() {
effect(() => {
this.setTrans().then();
});
}
async setTrans(): Promise {
switch (this.lang()) {
case Lng.en: await import('../translate/en').then(f => {this.trs.set(f.trans)}); break;
case Lng.uk: await import('../translate/uk').then(f => {this.trs.set(f.trans)}); break;
}
this.setHeader();
}
Technically it is correct.
You can shorten this.setTrans().then() to just this.setTrans(). Promises are not like Observables.
You are tracking the lang() here. I would track the Signals directly in the effect for better readability and use an untracked. So it could look like this:
constructor() {
effect(() => {
const lang = this.lang();
untracked(() => this.setTrans(lang))
});
}
async setTrans(lang: string): Promise {
switch (lang) {
case Lng.en: await import('../translate/en').then(f => {this.trs.set(f.trans)}); break;
case Lng.uk: await import('../translate/uk').then(f => {this.trs.set(f.trans)}); break;
}
this.setHeader();
}
@@RainerHahnekamp Thank you very much!
@@WebGarmony You're welcome
At 30:00, how can i initialize the state if the page gets loaded? Lets say we need the amount to be 1 if the page gets loaded AND if the productId changes?
It works with this.state() in ngOnInit. Is this a good approach?
The component initialses the state when the constructor runs. So you are very safe there.
No, try to avoid ngOnInit in this case. If I want to get the value of a Signal I try to use it in an effect or the template. There I don't have any issues, with Signals that aren't ready yet.
@@RainerHahnekamp
What if the selectedProductId is an input() ? I have this case at my code now where i dont know when to load the entity. In ngOnInit or via effect or via computed?
@@Heskmark Do you see a problem when you use the effect()? It is the last use case that I've showed. Makes perfectly sense. With ngOnInit you have the problem that it is one-timer. So if the id changes, you don't get informed. computed is not made for that use case.
Isn't use case 3 an example of propagation of state changes? I see a difference here using toObservable and then piping it to a switchMap to get the customer compared to the effect usage: the signals change is done in the observable subscription, and not inside of the effect.. I'm not sure of how toObservable works under the hood, though
Actually, there would no be a explicit subscription if we assign the result of the pipe to customer$ stream and use async
If at all, Use Case 3 is "ASYNCHRONOUS" propagation fo state changes. If it helps you can also say effect doesn't change a Signal it all, it just calls an asynchronous method and then it stops. Once that task we are very far away from the "juristication of an effect".
I don't see the usage of async is future proof. We know that Signal Components will come and then everything should be a signal in the template. Btw. toObservable is a wrapper for effect.
for valid effect use cases ... shouldn't we use rxMethod? I mean in most use cases... I think rxMethod is very powerful! You don't need "untracked" then.
This was not an ngrx/signals video, just vanilla angular signals
Hi, yes, as @codeSurvivor already said, this video has nothing to do with NgRx. It is native Angular and rxMethod is also using effect()
In your edit-customer component, you mention that the foobar computed needs to be called in the template in a reactive context in order for the computed run. Why don't you define your customer signal as the computed instead?
Beacuse the type of the computed would be a Promise. Can you provide a code snippet how your computed would look like?
@@RainerHahnekamp Ah yes, that is true! I cannot think of a way of avoiding the returned computed from being a promise. The only way I can think of avoiding using an effect is something nested like this. This of course relies rxjs and rxjs interop, and doesn't look nice either!
@Injectable()
class ManfredService {
doAsyncThing(value: number) {
return new Promise(resolve => {
setTimeout(() => resolve(value * 5), 1000);
});
}
}
@Component({
standalone: true,
template: `{{ myComputed() }}`,
changeDetection: ChangeDetectionStrategy.OnPush,
providers: [ManfredService],
})
export class ManfredComponent {
myInput = input.required();
manfredService = inject(ManfredService);
myComputed = toSignal(
toObservable(this.myInput).pipe(switchMap(value => from(this.manfredService.doAsyncThing(value)))),
);
}
@@RainerHahnekamp Sorry I had a response with a code snippet but must not have clicked 'reply'. I can't avoid returning a promise in the computed, you are right! I was however able to avoid using an effect by a mixture of rxjs and rxjs interop. something like:
myNewSignal = toSignal(toObservable(myInput).pipe(switchMap((value) => from(myService.returnPromise(value)))))
I think using an effect is definitely cleaner and requires less imports
@@seanclarke-1 If you say you can live without the switchMap, then definitely effect. If you say switchMap is important, then I'd do a manual subscription to the Observable and set the effect in its next callback.
I think we could expext to see some kind of deriveAsync to came up....
Yes, but I think a solution for these kind of reset patterns are even more important. At the moment, it is not very readable to do with it computed.
Support for asynchronous tasks will probably go hand in hand with the future of the HttpClient (speaking of optional RxJS).
great
Thanks.
36:31 readonly state = computed(() => { return { product_id : this.selectedProductID(), amount : signal(1) }; } )
Also for reactive forms I would suggest not to use effects but events if you need to react on state-changes ... effects have only a very very slim use-case like for an example triggering toasts, sending telemetry or logging ... what you did in this video is kinda forcing effects into scenarios in which other options are better e.g. using stores, child-components or events
but the worst thing you did is coming up with this "more readable" nonsense .. purely subjective and if you really think about it also not true in the slightest because you have to deal with asynchronous code
I’ve provided some examples so we can focus on practical scenarios rather than debating abstract concepts.
It would be great if you could pick one of the examples and show how you think it should be approached.
I’m eager to have a serious discussion and see what you have in mind, but refrain from using words like ‘nonsense.’
@@RainerHahnekamp sure .. 18:40 instead of updating the customer signal with set you could just define the customer signal as computed of id .. this in fact would be more readable because you don't have to jump up and down to understand what's going on and it would be declarative
@@mjdev-i1p
The only way how I see is:
customer = computed(() => this.customerService.byId(id))
That computed will in this case return a Signal. You could probably call the Signal in the template and use the async pipe (should work with Promises).
I am not sure if a Signal holding a Promise is a better solution but the actual problem will be, that you cannot have any consumers (other computeds) on that customer anymore. Because the Signal has no clue that a Promise can resolve, etc.
I've read an article describing a concept of an asynchronous Signal, but that would require that the framework also knows how to deal with it.
How would your approach look like?
@@RainerHahnekamp well it depends on what you try to achieve ... if you just need to consume the signal at this one instance then the approach as you described it would be completely fine ... however if you need to share the value between multiple consumers then I would use a signal-store
The only scenario in which i see an effect as the preferable solution is if you want to do a quick and dirty patch to something
@@mjdev-i1p Yes, so the use case was here for a single component. If the Signals gets accessed by multiple components, then I would expose it to a Service or would directly go with the SignalStore and I would pass the Signal to that service. But also here, a self-written service or the rxMethod of the SignalStore will use the effect for you. So you delegate it.
Small note: Having an effect in a service providedIn: root is always a little bit problematic. Because it runs over the whole application lifecycle and you might have to come up with manual destruction.