The more I know rxjs it's harder to not use it, because there are a lot of things, that are easier to accomplish than with signals (think scan, debounce, merge, withLatestFrom etc.). But yes, you have to keep track of all the (invisible) subscriptions because they can bite you if you forget a share at the right place. As always: failures have to be made to learn from them. And even a relatively simple component has often more events than state - I can't think of not using rxjs.
So after so much headache our team forced ourselves to use NgRx instead of our complete mess of observables and state services. The upside is the newer devs can use all the stores but the boilerplate to set it up is a bit daunting. Sooo using signals as redux lite might be a really interesting balance between the Cathedral of NgRx and the anarchy observables as state.
I know what you mean, I love ngrx but WE need to keep a close eye on our stores to keep them clean. On a medium project, I found NgRx Signal Store a very nice replacement for Component Store actually.
How I'm approaching signals at the moment: I'm just not. I don't need signals. Declarative rxjs is just fantastic. The only problem is most of the people in my team don't want to learn it. The other thing is, I think toSignal is a bad idea. This is because, in my experience, the initial arbitrary value we provide can cause problems in client code such as calculations in effects. For example, I calculated in an effect a default value for a form field (for when it is null); this did not work correctly with toSignal because the first set of arguments passed in contained the arbitrary value, not the db value. My main problem with signals is making asynchronous code synchronous with these arbitrary values. It goes against my developer intuition. There could be unexpected consequences of doing this.
I honestly think RXJS is not not necessary for a majority of what an app needs. Even the use of a store at all is often just over kill. I recently did a full app with barely using an RXJS call and almost no store state. After doing work like this for over 30 years I have come to the conclusion that a lot of this is developers wanting to architect solutions instead of just building what they need. Thinking out of the box goes a long way. For example, I created a facade API that does most of the heavy lifting and returned only what I need to the client for each page. The page preloads the entire page’s data (mostly) on route and then uses a shared service as context. It was simple, easy to debug and test and cut out a huge amount of boiler plating. This also meant that a lot of processing was pawned off on the facade API.
Actually, I don't think subscription from an observable steam to signal state makes code "Imperative". In React or any other framework, it's natural to do setState logic in UI's event handler, just like a two-way binding mechanism. Using rxjs to manage state is a nightmare, it requires high level of rxjs skill to achieve some basic and easy operations which signals can do. Which definitely harms the code readable and maintainable.
I operate under the definition of declarative meaning "everything that defines the behaviour of this entity is contained within its declaration", so with that definition anything that involves reassigning the value of something from outside of its declaration is imperative
@@JoshuaMorony fair enough, but just like what you said in previous videos, binding event handlers and "reassign" it to a (Behavior)Subject is also an Imperative way right? So, it's pointless to achieve a fully pure declarative style.
@@lightyagami5963 yes even the toSignal approach which I am saying is "more" declarative here, also still has imperative parts because user actions need to be propagated to the Subjects or whatever mechanism you are using via an imperative call - so (if we are using services anyway) we can't really have "fully" declarative code in Angular (even if we could I'm not convinced it would be worth it). So this is more a case of figuring out where best to draw the line.
Speaking of Zoneless.. as Angular/fire just appears to not be really updated any longer, does anyone have experience with just using native firebase library for Firebase access, in Angular? Any issues? I have to move away from Angular/fire, as our app is now zoneless
I'm yet to properly give SignalStore a go but I know it's great and I know a lot of people love it - my current preference is signalSlice (naturally, because I built it around what I like) but the APIs are very similar so signal store also feels quite natural to me. The main thing at odds with my own ideas around declarative code etc is the idea of using patchState imperatively, but the existence of patchState also doesn't mean I can't also write declarative code with SignalStore - I'll need to play with it
The issue with patchState() is not only in imperativeness but also in mutating the global state. It can easily cause unexpected side effects, endless loops and other nasty surprises. Look, people created a whole programming language to avoid exactly this :) (I mean Rust)
I still doesn't understand how to use signals-only approach properly on practice in any case when it's need to call a function after a signal has been changed. Like, when signals-state was chaged I need load http data and re-render a chart. How should I do this with signals only? Considering that effect are forbidden by the Angular documentation guides.
computedAsync from ngxtension does provide a reasonably nice way to go about this in a way that feels like you're just using signals, but it is still technically using RxJS under the hood. But yes, with no abstractions the way to achieve a "signal only" style approach for async situations (and to be clear I do not like this approach) is to use effects with allowSignalWrites
"Considering that effect are forbidden by the Angular documentation guides" this isn't true. they only caution you on using allowSignalWrites because most things can be solved with computed and if you aren't careful can cause issues, but that does not mean you can't use it
Your content is high quality, relevant, and I really enjoy it. However, it would be good to include some reflection on the challenges faced by Angular, particularly in the context of RxJS/Signal patterns. It’s concerning that it might take an Angular expert an entire year to settle on an effective pattern for managing reactivity within Angular applications. To clarify, I believe the root cause lies in the introduction of signals and the potential impedance mismatch it introduces when compared to the existing async primitive (RxJS).
See also: Reactive Forms vs Model Binding. See also: Outputs vs Callbacks. See also: Promises vs Observables/Signals. See also: Shared Services vs ViewChildren vs Injecting Children. Etc etc etc As an ex-react developer, I was promised "Angular apps look the same" but I find that if a problem had two different solutions in React, it has 5 in Angular.
I'm not sure if it addresses specifically what you are talking about, but I do have some videos like this one: ruclips.net/video/iA6iyoantuo/видео.html which essentially focuses on the question of "why would Angular want to introduce a signals primitive when RxJS can already do essentially the same thing" And I think we are in somewhat of an unavoidable hard period with Angular where there is a lot of new stuff, and no consensus on best practices around the new things. But I think we are starting to get to a point where different preferred patterns are emerging, and for most people who will adopt signals a little bit later down the line they won't need to mess with experimentation so much.
@@BenjaminLeeds yeah, you are quite right. And also some very experienced Angular expert like to push their own custom store or stuff like that, and that's not helping in my opinion.
I ran into a bug with my reducers, sources and switch map. I think the root was the double subscription. In my switch map I would return EMPTY if the request was not needed but my status would get stuck in the loading because of the reducer. I couldn't fix it so I just put the reducer in the switch map.
This video was really useful, thank you so much. I have a question: for the sources, we have retry$, currentPage$, and error$. I think error$ will be needed in almost every service. Is it a good idea to create a new model to encapsulate those sources? For instace creating a model like SubjectData derived from Subject? I thought like this might reduce the boilerplate code.
Maybe I'm missing a point here but if error$ is declared for the coming API errors, I'm catching and handling them in an interceptor and don't bring them into my component at all. Only successes are handled in my components. Please let me know if error$ is referred to something else in the context.
Sources can also be user actions e.g. in the example in the vid we have "retry", "error", and "currentPage" sources - retry and currentPage are triggered in response to user actions, error is called from within the code. So for submitting a form can have some form of "submit$" source that you next in response to ngSubmit, you could either supply that source with data directly, or when that source emits you switch/map to whatever you want (e.g. the form data which then gets POSTed)
The goal here was to work directly with the native concepts in Angular to give a better sense of the fundamental concepts/ideas which libraries abstract/hide. To be clear though I'm not against using libraries/utilities and do use them, generally for me that's either just connect or signalSlice but TanStack Query is something I've been meaning to try for a while (Loadoff I don't really know anything about)
You are right. For newbies, Redux is better, and it is pointless to expect them to write a perfectly declarative code. I was there, I know it from my own experience. And when one can notice the downsides of that flexibility, they will migrate to a more declarative approach. Nothing but experience can help them.
Shots fired. I don't consider myself a newbie (12 years experience, 4 in Angular), and I've given both approaches fair shots, but have decided that the Redux style is easier to maintain. The reactive style has too many cascading effects that make it hard to debug and reason about. Not to mention the cumbersome mechanics in RxJs.
just make it easy to write and explain, all declarative code is nice is theory but only works if you're in a team with 10+ experienced developers with the same mindset. It's good to sacrifice some 'good' code for 'bad' code to not make everything over complex. Do you even understand it well enough to explain it to the 5 new junior devs? What if you introduced the all declarative way (tosignals in this case?) but can't solve the giant bug it caused? Do you even know how to unit test it?
here's too many layers and too much abstraction, Angular jobs are much fewer than React and if they keep adding all this Angular only sh!t it's going to put off even more devs. Relearning everything ever few years to get same result is poitless jerking off. Love your vids!
@@qwerty-or1yg I don't think the pros of using them outweigh the cons. Okay, they're “simpler” to control than observables, but in exchange for that you..: - Lose the 100% declarative nature of a data change pipeline that you get in an approach using 100% RxJs. - Mix two different things in this flow, and have to deal with them in different ways. - You lose the ability for the data to be subscribed to and controlled entirely by Angular in the template, going back a little to the first point of having code that is completely declared and “flowing” as the data streams are fed. In exchange for what exactly? Lower learning curve for beginners? I don't think it's worth it, honestly.
input, output, viewchild and viewcontent signals are really nice. Also model signals for dual bindings. Don't have to write that much boilerplate. State management is better with signals. And you can still use toSignal or toObservable to switch between worlds. Since it is preview, it contains some bugs. I recommend at least 17.3.x for signals to be helpful for interoperability
@@MarcusKaseder yeah, agree, reactive inputs are nice, and can make some components quite simpler than before. But I can understand this comment. Also, the problems arise very quickly with signals, when you try to make side effects and stuff like that. I would say that Angular is adopted for its opinionated way, and as this video shows, it lost a bit of it. Hopefuly much clearer patterns will arise, because I myself don't like the mix of observables and signals.
this whole declarative thing has become like a cult, honestly, I don't agree with ' sacrificing a small amount of declara-ness' because it didn't make the code better so you didn't lose anything.
Even in this small example I think the small loss of "declarative-ness" does still have a noticeable downside. Take the "status" for example, in the more declarative version if we want to know what it is and how its behaviour is defined the only place we have to look is at the declaration of the "status$" stream. With the redux style approach (which to be clear I'm not against and am sort of advocating for here) if you look at the declaration of "status" all you can see is its initial value. To understand how it behaves you need to search for all instances where it is being imperatively updated. With the approach in the video, this is at least limited to only occurring within the subscription to the sources rather than potentially coming from anywhere, and since the value is being set into another reactive mechanism (the signal) we can still derive other things declaratively from that.
My next newsletter goes out tomorrow if you want to sign up: mobirony.ck.page/4a331b9076
The more I know rxjs it's harder to not use it, because there are a lot of things, that are easier to accomplish than with signals (think scan, debounce, merge, withLatestFrom etc.). But yes, you have to keep track of all the (invisible) subscriptions because they can bite you if you forget a share at the right place. As always: failures have to be made to learn from them. And even a relatively simple component has often more events than state - I can't think of not using rxjs.
I can never go back from Signals.. it's SO nice.. and with zoneless it's just great
So after so much headache our team forced ourselves to use NgRx instead of our complete mess of observables and state services. The upside is the newer devs can use all the stores but the boilerplate to set it up is a bit daunting. Sooo using signals as redux lite might be a really interesting balance between the Cathedral of NgRx and the anarchy observables as state.
I know what you mean, I love ngrx but WE need to keep a close eye on our stores to keep them clean.
On a medium project, I found NgRx Signal Store a very nice replacement for Component Store actually.
I feel Ngrx signal store more imperative that tradicional ngrx store
I don't see how observables are anarchy. Quite the opposite, as Joshua will tell you, they are a great way of simplifying state.
@@tarquin161234 I really meant using services to store and handle state.
How I'm approaching signals at the moment: I'm just not. I don't need signals. Declarative rxjs is just fantastic. The only problem is most of the people in my team don't want to learn it.
The other thing is, I think toSignal is a bad idea. This is because, in my experience, the initial arbitrary value we provide can cause problems in client code such as calculations in effects. For example, I calculated in an effect a default value for a form field (for when it is null); this did not work correctly with toSignal because the first set of arguments passed in contained the arbitrary value, not the db value.
My main problem with signals is making asynchronous code synchronous with these arbitrary values. It goes against my developer intuition. There could be unexpected consequences of doing this.
My dopamine somehow increases whenever I see RxJs with Signals 😂😂
I honestly think RXJS is not not necessary for a majority of what an app needs. Even the use of a store at all is often just over kill. I recently did a full app with barely using an RXJS call and almost no store state. After doing work like this for over 30 years I have come to the conclusion that a lot of this is developers wanting to architect solutions instead of just building what they need. Thinking out of the box goes a long way. For example, I created a facade API that does most of the heavy lifting and returned only what I need to the client for each page. The page preloads the entire page’s data (mostly) on route and then uses a shared service as context. It was simple, easy to debug and test and cut out a huge amount of boiler plating. This also meant that a lot of processing was pawned off on the facade API.
Actually, I don't think subscription from an observable steam to signal state makes code "Imperative". In React or any other framework, it's natural to do setState logic in UI's event handler, just like a two-way binding mechanism.
Using rxjs to manage state is a nightmare, it requires high level of rxjs skill to achieve some basic and easy operations which signals can do. Which definitely harms the code readable and maintainable.
I operate under the definition of declarative meaning "everything that defines the behaviour of this entity is contained within its declaration", so with that definition anything that involves reassigning the value of something from outside of its declaration is imperative
@@JoshuaMorony fair enough, but just like what you said in previous videos, binding event handlers and "reassign" it to a (Behavior)Subject is also an Imperative way right?
So, it's pointless to achieve a fully pure declarative style.
@@lightyagami5963 yes even the toSignal approach which I am saying is "more" declarative here, also still has imperative parts because user actions need to be propagated to the Subjects or whatever mechanism you are using via an imperative call - so (if we are using services anyway) we can't really have "fully" declarative code in Angular (even if we could I'm not convinced it would be worth it). So this is more a case of figuring out where best to draw the line.
Speaking of Zoneless.. as Angular/fire just appears to not be really updated any longer, does anyone have experience with just using native firebase library for Firebase access, in Angular? Any issues? I have to move away from Angular/fire, as our app is now zoneless
And how do we implement loading signal in the redux way? Create a new state of every loading component part?
What is your opinion on ngrx signal store?
I'm yet to properly give SignalStore a go but I know it's great and I know a lot of people love it - my current preference is signalSlice (naturally, because I built it around what I like) but the APIs are very similar so signal store also feels quite natural to me. The main thing at odds with my own ideas around declarative code etc is the idea of using patchState imperatively, but the existence of patchState also doesn't mean I can't also write declarative code with SignalStore - I'll need to play with it
The issue with patchState() is not only in imperativeness but also in mutating the global state. It can easily cause unexpected side effects, endless loops and other nasty surprises. Look, people created a whole programming language to avoid exactly this :) (I mean Rust)
I still doesn't understand how to use signals-only approach properly on practice in any case when it's need to call a function after a signal has been changed. Like, when signals-state was chaged I need load http data and re-render a chart. How should I do this with signals only?
Considering that effect are forbidden by the Angular documentation guides.
computedAsync from ngxtension does provide a reasonably nice way to go about this in a way that feels like you're just using signals, but it is still technically using RxJS under the hood. But yes, with no abstractions the way to achieve a "signal only" style approach for async situations (and to be clear I do not like this approach) is to use effects with allowSignalWrites
"Considering that effect are forbidden by the Angular documentation guides" this isn't true. they only caution you on using allowSignalWrites because most things can be solved with computed and if you aren't careful can cause issues, but that does not mean you can't use it
I've been in camp #2, using RXJS sparingly but not eliminating them.
Your content is high quality, relevant, and I really enjoy it. However, it would be good to include some reflection on the challenges faced by Angular, particularly in the context of RxJS/Signal patterns. It’s concerning that it might take an Angular expert an entire year to settle on an effective pattern for managing reactivity within Angular applications. To clarify, I believe the root cause lies in the introduction of signals and the potential impedance mismatch it introduces when compared to the existing async primitive (RxJS).
See also: Reactive Forms vs Model Binding. See also: Outputs vs Callbacks. See also: Promises vs Observables/Signals. See also: Shared Services vs ViewChildren vs Injecting Children. Etc etc etc
As an ex-react developer, I was promised "Angular apps look the same" but I find that if a problem had two different solutions in React, it has 5 in Angular.
I'm not sure if it addresses specifically what you are talking about, but I do have some videos like this one: ruclips.net/video/iA6iyoantuo/видео.html which essentially focuses on the question of "why would Angular want to introduce a signals primitive when RxJS can already do essentially the same thing"
And I think we are in somewhat of an unavoidable hard period with Angular where there is a lot of new stuff, and no consensus on best practices around the new things. But I think we are starting to get to a point where different preferred patterns are emerging, and for most people who will adopt signals a little bit later down the line they won't need to mess with experimentation so much.
@@BenjaminLeeds yeah, you are quite right. And also some very experienced Angular expert like to push their own custom store or stuff like that, and that's not helping in my opinion.
How do you use takeUntilDestroy without injecting a DestroyRef?
New feature in angular 16
Use it at the constructor level - either in the constructor or field definition.
I ran into a bug with my reducers, sources and switch map. I think the root was the double subscription. In my switch map I would return EMPTY if the request was not needed but my status would get stuck in the loading because of the reducer. I couldn't fix it so I just put the reducer in the switch map.
This video was really useful, thank you so much. I have a question: for the sources, we have retry$, currentPage$, and error$. I think error$ will be needed in almost every service. Is it a good idea to create a new model to encapsulate those sources? For instace creating a model like SubjectData derived from Subject? I thought like this might reduce the boilerplate code.
Maybe I'm missing a point here but if error$ is declared for the coming API errors, I'm catching and handling them in an interceptor and don't bring them into my component at all. Only successes are handled in my components. Please let me know if error$ is referred to something else in the context.
@@codeme8016 in some circumstanced you might wanna implement something individual. You know in the interceptors we make generic things.
I find ng extension utils more useful to work along with signals.
How would you handle stateful forms? What would the source be for a submit action?
Sources can also be user actions e.g. in the example in the vid we have "retry", "error", and "currentPage" sources - retry and currentPage are triggered in response to user actions, error is called from within the code. So for submitting a form can have some form of "submit$" source that you next in response to ngSubmit, you could either supply that source with data directly, or when that source emits you switch/map to whatever you want (e.g. the form data which then gets POSTed)
I noticed the code in the video is different than the code in the git repo. Is there a reason for that? Example no shareReplay etc.
What is the point of calling toSignal? What is the benefit? Why not to use just selector with rxjs pipe(map) and bind with async pipe?
because then you have to use an async pipe and you can't use the results in computed or effect
What's the best approach for api request?
.subscribe or toSignal ?
Both of these approaches work with with async/api requests - the example in the video includes this scenario (loading the articles)
toSignal internally calls subscribe
@@yankotliarov9239 then where does the unsubscribe happens?
@@mansoorabdullah when component is destroyed
@@mansoorabdullah also api calls autocomplete themselves after getting the result
Simply put, Signals for states and Rxjs for events
I feel like TanStack Query or Loadoff can simplify the status and error streams. Your thoughts?
The goal here was to work directly with the native concepts in Angular to give a better sense of the fundamental concepts/ideas which libraries abstract/hide. To be clear though I'm not against using libraries/utilities and do use them, generally for me that's either just connect or signalSlice but TanStack Query is something I've been meaning to try for a while (Loadoff I don't really know anything about)
Yes TanStack Query will simplify the code, buuuut is still experimental…
You are right. For newbies, Redux is better, and it is pointless to expect them to write a perfectly declarative code. I was there, I know it from my own experience. And when one can notice the downsides of that flexibility, they will migrate to a more declarative approach. Nothing but experience can help them.
Shots fired. I don't consider myself a newbie (12 years experience, 4 in Angular), and I've given both approaches fair shots, but have decided that the Redux style is easier to maintain. The reactive style has too many cascading effects that make it hard to debug and reason about. Not to mention the cumbersome mechanics in RxJs.
just make it easy to write and explain, all declarative code is nice is theory but only works if you're in a team with 10+ experienced developers with the same mindset. It's good to sacrifice some 'good' code for 'bad' code to not make everything over complex. Do you even understand it well enough to explain it to the 5 new junior devs? What if you introduced the all declarative way (tosignals in this case?) but can't solve the giant bug it caused? Do you even know how to unit test it?
here's too many layers and too much abstraction, Angular jobs are much fewer than React and if they keep adding all this Angular only sh!t it's going to put off even more devs. Relearning everything ever few years to get same result is poitless jerking off. Love your vids!
skill issue
I found out... not using signals at all
The more I use it, and the more I see content about it, the more I think Signals was a move in the wrong direction.
How so? I honestly love signals so far.
@@qwerty-or1yg
I don't think the pros of using them outweigh the cons. Okay, they're “simpler” to control than observables, but in exchange for that you..:
- Lose the 100% declarative nature of a data change pipeline that you get in an approach using 100% RxJs.
- Mix two different things in this flow, and have to deal with them in different ways.
- You lose the ability for the data to be subscribed to and controlled entirely by Angular in the template, going back a little to the first point of having code that is completely declared and “flowing” as the data streams are fed.
In exchange for what exactly? Lower learning curve for beginners? I don't think it's worth it, honestly.
No man
input, output, viewchild and viewcontent signals are really nice. Also model signals for dual bindings.
Don't have to write that much boilerplate. State management is better with signals. And you can still use toSignal or toObservable to switch between worlds.
Since it is preview, it contains some bugs. I recommend at least 17.3.x for signals to be helpful for interoperability
@@MarcusKaseder yeah, agree, reactive inputs are nice, and can make some components quite simpler than before.
But I can understand this comment.
Also, the problems arise very quickly with signals, when you try to make side effects and stuff like that.
I would say that Angular is adopted for its opinionated way, and as this video shows, it lost a bit of it. Hopefuly much clearer patterns will arise, because I myself don't like the mix of observables and signals.
first 😎
this whole declarative thing has become like a cult, honestly, I don't agree with ' sacrificing a small amount of declara-ness' because it didn't make the code better so you didn't lose anything.
Even in this small example I think the small loss of "declarative-ness" does still have a noticeable downside. Take the "status" for example, in the more declarative version if we want to know what it is and how its behaviour is defined the only place we have to look is at the declaration of the "status$" stream. With the redux style approach (which to be clear I'm not against and am sort of advocating for here) if you look at the declaration of "status" all you can see is its initial value. To understand how it behaves you need to search for all instances where it is being imperatively updated. With the approach in the video, this is at least limited to only occurring within the subscription to the sources rather than potentially coming from anywhere, and since the value is being set into another reactive mechanism (the signal) we can still derive other things declaratively from that.