My go to way to manage state in Angular applications

  Рет қаралды 42,862

Joshua Morony

Joshua Morony

Күн бұрын

Пікірлер: 69
@bamboo6044
@bamboo6044 Жыл бұрын
If you haven't already, it might be a good idea to make an updated version of this, perhaps create a service for CRUD that uses generics and can be extended and used for various API endpoints
@jaredwilliams8621
@jaredwilliams8621 Жыл бұрын
I have implemented the "service with a subject" pattern in several applications, and it works great for sharing the data from the service to the components. However, I feel that there isn't a lot of examples out there demonstrating how the component is supposed to share new/modified data back with the service in a reactive way.
@SuperQuwertz
@SuperQuwertz Жыл бұрын
I came here as I want to know more about that too
@go41000
@go41000 Жыл бұрын
@@SuperQuwertz any luck? is the data availalbe on page refresh?
@SuperQuwertz
@SuperQuwertz Жыл бұрын
I use Svelte so I ended up with the value of the component getting set by the stream and nexting the stream if the component emits changes@@go41000
@DD-vc7fq
@DD-vc7fq Жыл бұрын
My main advice here would be to implement all of the logic inside services, and handle only display stuff in the components. But, if there is something you want to do inside component that will change the data and also notify the service that the data has been changed, that can be done easily. Imagine if we have a Component and a ComponentService. Inside ComponentService you have: someSubject = new BehaviourSubject(0); ---- Inside Component you have: someSubject = this.componentService.someSubject; constructor(private componentService: ComponentService) { } onClick() { this.someSubject.next(1); } What will happen here is the value of someSubject changes to 1 inside component, but it also changes to 1 inside service as well, because we defined that someSubject from Component is equal to someSubject from ComponentService (if anyone wonders why the changes on one subject makes the same changes on another subject, read about shallow copies). My general advice is: make a service for each component you make. Handle all of the logic inside services (if possible). Obviously, there will be times when you simply need to handle the logic inside components (prime example is if you want to change the data inside AfterViewInit() lifecycle hook, which is a hook that services don't have since they don't have html templates).
@trevormontgomery6795
@trevormontgomery6795 11 ай бұрын
Can you pass a parameter to the getter in the service? You could call next in the getter
@niravparsana
@niravparsana 2 жыл бұрын
Very helpful topic. Please do video on NgRx as it is more flexible for managing state in complex application. It would be good if you start with basic topics as NgRx is wide subject.
@dalu_
@dalu_ Жыл бұрын
ngrx has so much boiler plate. idk if it's more flexible, but ok, this comment is a year old now.
@stephenjames2951
@stephenjames2951 Жыл бұрын
Clear and concise description of the method used
@NvmThemHereIAm
@NvmThemHereIAm Жыл бұрын
I instinctively created a similar pattern (as in not making the subject private and accessing it straight away). Thank you for this explanation!
@jacobshomali5434
@jacobshomali5434 2 жыл бұрын
I tried using services and observables like this in angular but couldn't quite get it to work. The solution I came to eventually was to use redux instead but I'm glad I can finally figure out how to do it this way.
@AdrienSAULNIER
@AdrienSAULNIER Жыл бұрын
Nice video, ty ! Some questions : - How to set/handle UI state in your example (articles loading) into the service ? Do you create a new observable such as loading$ (or callState$ which represents the actual HTTP call status) or a state object containing the array of articles AND the ui state in the same object ? - How to handle error ? - How to handle substate (a child object by example, which depends of articles feature) which has is own ui state too ? Do you create new service or do you manage this substate into the ArticlesService ? I try and read so many many (many...) things and I never found the best (and universal) approach for those cases. It breaks my brain and raises doubts... Ty !
@JoshuaMorony
@JoshuaMorony Жыл бұрын
Personally if I am dealing with loading/success/failure sorts of states I like to use NgRx Component Store - but for a more simple approach you could do something like have an ngIf tied to the observable stream, and then provide an "else" template for loading that is displayed if the ngIf fails (which it will if the observable stream has not emitted yet). I've got some other videos on this. Different ways you can go about handling errors - again, Component Store provides some nice patterns for this and is generally what I would prefer, but there are also nice patterns like having a separate stream specifically for errors - Again, I have some more videos on both of these topics It depends on the situation, but generally if I had some child component I would have the parent component pulling in the stream from the service, and then passing that child component values from the stream as an input (using the async pipe)
@AdrienSAULNIER
@AdrienSAULNIER Жыл бұрын
​@@JoshuaMorony Thank you for your answers 🙏 About the ngIf, I don't know If I do wrong, but I'm always use a callState$ string obs which reflects the http call status, then display a template depends from its value (instead of dealing with properties such as "loading", "loaded", ...). What's your opinion about it ? The ngIf seems good in case you have a simple data to load just one time, but when you're working with paginated data by example, you need to show "loading" template after each page changes... Is extends ComponentStore into a Service provided in root a good practice, in some cases ? By example, if you want to share some states from multiple components which they're not in the same tree ? And the last question: Let's imagine we are a three level component tree: Would you be shocked if thethe 1rst include your ArticlesService and the 3rd too? Knowing that the 3rd has complex actions and uses other observables than the 1rst. Ty for your time :)
@luismpcunha
@luismpcunha 2 жыл бұрын
Good info, will definitely be using the approach of separating getting all of the data from getting only the new elements going forward.
@EverydayJavaScript
@EverydayJavaScript 2 жыл бұрын
Nice video. This helped me fix one of the issues in my project.
@ksivasuriyaprakash9976
@ksivasuriyaprakash9976 2 жыл бұрын
Please post a video about NgRx.
@kflo411
@kflo411 2 жыл бұрын
You should add a note about how you go against the grain in your naming of the BehaviorSubject variable: the dollar sign suffix is by-and-large used just for Observables. The BehaviorSubject of course is an observable by nature, but even you made an Observable/Subject distinction in your getter method. This is another distinction worth at least noting.
@JoshuaMorony
@JoshuaMorony 2 жыл бұрын
Interesting, I've never considered this to be honest - I've been quite intentionally using the dollar sign suffix for BehaviorSubjects and was under the impression this is what most other people were doing too (it's also what seems to make the most sense to me too), but I could certainly be wrong about that.
@pawekoaczynski4505
@pawekoaczynski4505 Жыл бұрын
2:15 I'm pretty sure you are still able to call the `next` method. Heah, you will get TypeScript error, but you can make it go away with @ts-ignore. I believe that adding the type annotation doesn't really do to the underlying object's structure - it still has the same methods, TypeScript doesn't make the fields private. Combined with explicitly adding return type makes me don't really like this solution. Though I can see other people seeing my comment as a nitpick :p
@nektworks
@nektworks Жыл бұрын
This is correct. The getArticles function returns a BehaviorSubject. The reason TypeScript isn't erroring this is because technically, the BehaviorSubject class extends Subject class, which extends Observable class, which means that a BehaviorSubject can act as an Observable. Instead of creating a getArticles function, you can also use the asObservable function for your BehaviorSubject, like this: private articlesSubject = new BehaviorSubject; public articles$ = articlesSubject.asObservable();
@bamboo6044
@bamboo6044 Жыл бұрын
@@nektworks I just wanted to comment the same, also, no need for public keyword as props are public by default.
@stunna4498
@stunna4498 8 ай бұрын
where you start the init function ?inside the service? in the app component? how should we initialize the article$?
@jayasaichandmaheshmunagala2135
@jayasaichandmaheshmunagala2135 2 жыл бұрын
Love to see ngrx content.please make it
@satheshkumar5906
@satheshkumar5906 2 жыл бұрын
would be useful if you could prepare a tutorial on best practices using ngrx
@f19-x9k
@f19-x9k Жыл бұрын
Thank you very much for the insight :)
@ilclaudio123
@ilclaudio123 2 жыл бұрын
Thank you for this intertesting video :-)
@TravisSomaroo
@TravisSomaroo Жыл бұрын
Hey Josh, very helpful topic. I wanted to ask would this approach update the UI based the database has been updated. So for example if I create a new article would the list of articles be updated without me having to refresh the page? Thanks in advance. :)
@tobihbestpaul1444
@tobihbestpaul1444 2 жыл бұрын
please a video for the NgRx store, some applications need "order" and less freedom.
@will-ever
@will-ever Жыл бұрын
Would public *readonly* articles$ be better in the service than a private one with a method? For the cases when data is requested only in init, of course...
@quickmaths4762
@quickmaths4762 Жыл бұрын
Why not start behavioursubject with null? It's less ambiguous imo. Articles could be empty when arrived. But null only before arrived @Joshua
@trustingod0
@trustingod0 2 жыл бұрын
I learned a lot from your video. I was wondering would it be a best practice to update my list of employees only when i add a new employee and not make an http call to the server except for in the case when the user wants to look at the list of employees when the application first begins and to give an initial stream of data to the observable. But then i worry about memory and holding a lot of data in the observable, is this feasible? Is holding the data in memory more efficient than making an API call to the server? Thanks !!!
@go41000
@go41000 Жыл бұрын
Will the data be available on page refresh?
@Mystearica
@Mystearica 2 жыл бұрын
Very nice video as always. How do you handle errors this way? In the app we are working, we have to show the error when a 200 ok response with an specific object, insted of the one we are expecting, so we need to add ifs always inside the subscribe to check it.
@JoshuaMorony
@JoshuaMorony 2 жыл бұрын
My go to approaches are either using a separate error stream (one that will use ignoreElements to ignore normal emissions, and a catchError that will return a stream of the error value), or using Component Store to handle the error states. A few of my recent videos talk about these approaches.
@kunalvirk
@kunalvirk Жыл бұрын
I tried this but struggling to make it work. So I have about four services `UserInfo`, `TeamService`, `ProjectService` & `FilterService`. They depend on each other in the mentioned order i.e. `FilterService` depends on `ProjectService` which depends on `TeamService` which depends on `UserInfo`. `UserInfo` does the authentication via Auth0. So in the application when I try to get userInfo, I get undefined (ofcourse it is all asynchronous) but how to make it work. I don't want to introduce my application to NgRx if it can be handled by angular. Can you please help on this?
@FinanzMinimalist
@FinanzMinimalist Жыл бұрын
I don't think this is (not yet) a state management system. 1. You miss a function to set the state from the outside. 2. You miss the getValue method of BehaviorSubject to get the last emitted value directly (important for usage in components). It is more like a better way of getting data from an api and present it as an BehaviorSubject + add a function for filtering. Btw: I really like your videos :)
@__emzd
@__emzd 9 ай бұрын
I don't get the purpose of declaring articles$ private then exposing it unmodified with the getArticles,..yes typescript may fail to compile but the returned value is technically a BehaviorSubject and you'd still be able to call next() and emit a new value from outside. A safer option is to return articles$.asObservable()
@user-jtwe1xrf2n
@user-jtwe1xrf2n Жыл бұрын
What about the subscription inside the ArticlesService? Are you not unsubscribing from that?
@JoshuaMorony
@JoshuaMorony Жыл бұрын
Technically it would be safer to do this and I would generally advise it, but an observable from the HTTP client will complete after one emission (although I think still piping take(1) to be explicit is worthwhile). In a more robust example, I would generally want to run initialisation logic like this inside of something like a NgRx Component Store effect.
@KeganVanSickle
@KeganVanSickle 2 жыл бұрын
Observables and updating their state is how I manage large datasets.
@FrancescoDeGiorgio
@FrancescoDeGiorgio 2 жыл бұрын
One question: I have the following flow: - a service which reads "news" items from a database, - the "news" interface with title, text, image, etc. - the "homepage" view (ts & html) if I use a local json file and I update one of its values, it automatically update the view with the new values but, if I read the news-items from a database the only way to get the updates values is to call an "update" function every X seconds or entering the view again. There is any chance that it takes automatically the update values from the database or to automate the refresh-call ? (something similar happens with firebase if i'm not wrong)
@JoshuaMorony
@JoshuaMorony 2 жыл бұрын
You can do polling with RxJS quite nicely if you want, the basic idea would be to use a 'timer' creation operator from RxJS which is basically just like a setInterval. Let's say the timer emits every 2 seconds, you could then use a switchMap operator to switch that timer observable stream to the observable stream from your HTTP request, which would return you the results from the server. This is certainly doable, but you might also want to investigate other ways to achieve this without needing to poll a server, but that would lie outside of RxJS (e.g. maybe you use a web socket and then integrate that with your stream, or maybe you have something like Firestore which can also provide a stream of updates).
@mfpears
@mfpears 2 жыл бұрын
8:30 It won't scale well without selectors, no matter what rules you follow.
@123vimalan
@123vimalan 2 жыл бұрын
Please do a video in Ngrx.
@JoshuaMorony
@JoshuaMorony 2 жыл бұрын
A couple of my recent videos are on NgRx :)
@JZubero
@JZubero 2 жыл бұрын
Do you see any strong benefit in using the BehaviorSubject opposed to a regular Observable with the shareReplay and startWith operators in your specific scenario? Of course, if you'd be pushing new data from different "places" inside of your service, the Subject-based approach would be the way to go. And: +1 for some NgRx vids! Thanks ✌
@JoshuaMorony
@JoshuaMorony 2 жыл бұрын
The key benefit to BehaviorSubject here is that it gives you that initial value and will always supply the last value, so that's probably easier than manually using additional operators to achieve the same thing, but of course you can do whatever suits your circumstance best or just what you like doing - the main idea is that you can get an observable stream of data from your service, you could create that stream however you like.
@hansschenker
@hansschenker 2 жыл бұрын
you write less code - less code is less possibiities for errors!
@JZubero
@JZubero 2 жыл бұрын
​@@hansschenker Transforming the stream of the HTTP request with shareReplay and startWith - instead of handling the BehaviorSubject - could actually reduce the lines of code needed. But as Josh said, it really depends on the specific use case. Still agreeing on your statement about less code, less bug potential 🙃
@Don_Giovanni
@Don_Giovanni 2 жыл бұрын
What's your reasoning for subscribing to an observable and then creating a new one in a service? IMO the beauty of rxjs lies in the pipe methods that let you manipulate the data without the need to break the chain along the way. And if you need to get a value on subscription you can just use one of the replay methods, afaik.
@JoshuaMorony
@JoshuaMorony 2 жыл бұрын
The point in the video was to demonstrate that we can get data however we want - sync or async - and then just emit that on the BehaviorSubject when it's ready. I do agree with what you're saying though, the fact that I used an observable to get the data to emit on the BehaviorSubject could be confusing. If I wasn't just trying to show how BehaviorSubject works ideally I would 1) Have a articles$ member variable to store the HttpClient observable 2) Call getArticles which will either set articles$ to the stream returned from HttpClient if it isn't defined yet, or if it has just return articles$ directly 3) When creating the HttpClient stream, pipe the shareReplay operator so that future requests for articles$ also return the value from the server But I don't think explaining all of that would've been a good idea for this video since it is more beginner oriented - coming up with simple self contained examples with no flaws is hard :)
@ValerioComo
@ValerioComo Жыл бұрын
I think init method is an anti-pattern
@ps-pu5dd
@ps-pu5dd 2 жыл бұрын
ng rx no? bra
@davidNelson8875
@davidNelson8875 9 ай бұрын
It is not recommended to call next of another subject inside subscribe
@EduardLepner
@EduardLepner 2 жыл бұрын
Not only this video useless for an experienced developer but also harmful for the beginners. This approach completely ignores the huge power of rxjs with caching with shareReplay and startWith which is stated in the comments below but also introduces code smell in init() method which shifts this responsibility to UI component thus making such service way worse than a 'classical' one.
@JoshuaMorony
@JoshuaMorony 2 жыл бұрын
Unless I'm mistaken, BehaviorSubject already provides a hot observable so the responses in this case would be cached/shared by default (my understanding is a BehaviorSubject is basically just a shortcut for Subject + shareReplay + startWith). I do have a more advanced article on caching with observables here: eliteionic.com/tutorials/caching-and-sharing-firestore-data-with-rxjs-sharereplay/ but it's not really the point of this video. Maybe I'm wrong to teach it this way, but my opinion is that it's fine to provide a simplistic example to teach a concept and that making everything adhere to best practices can get in the way of the learning for beginners - I want to introduce a couple of concepts at a time not everything at once. I agree using an init method here is not ideal, but I think it makes the example easier. If I want to do videos on more advanced things I will generally make a video that focuses on just that, like the concepts you are talking about: kzbin.info/www/bejne/fmaXY42JrtqVqKc Anyway I've got a comment similar to yours a couple of times so I'll pin this so people can see this extra detail if they want.
@EduardLepner
@EduardLepner 2 жыл бұрын
@@JoshuaMorony Yes, indeed, BehaviourSubject provides last emitted value to the observers but if it was your intent init() method should have been declared as private and used in the constructor of that service (which leads the data to be preloaded, ofc). Otherwise, the first consumer of that service (HomePage in your example) must somehow guess that it's its responsibility to call this method. And if the application is made of chains services calling each other it might result in very hard to troubleshoot problem when everything works fine but results don't show up. I agree that beginner tutorials should be made of simple examples but this particular example just kills the whole point of rxjs in Angular and leads to incorrect overall architecture understanding. Sorry, if I seemed rude but I should have stated that :)
@JoshuaMorony
@JoshuaMorony 2 жыл бұрын
​@@EduardLepner All good! I think conversations like this can be great to help add colour to a simple video if it's kept constructive. If I were to go with the approach of an "init" method in a real application (which I generally wouldn't, but I don't think it is necessarily wrong) I would have it be called from the root component so that it is initialised when the application is started. I think this is preferable to using the constructor as it is generally best to avoid doing work in constructors wherever possible - primarily because it can make testing difficult. What I would actually do in a real application is have the initialisation happen whenever the getArticles method is first called - although this might depend on what the method is supposed to do exactly, if it needs to load data from a server then I might want to trigger it earlier, in which case I might actually rely on an init method.
@gildas_dev
@gildas_dev 2 жыл бұрын
@@JoshuaMorony Personally I use to put the init in the constructor. The first time the constructor is called is the first time the service is used because of DI. This way it is safe to manage lazy loading errors I think.
@JoshuaMorony
@JoshuaMorony 2 жыл бұрын
@@gildas_dev I think it's fine to do it that way if that's what you want - the only real downside (at least the only one I can think of) is that in a test environment it is going to mean that creating the service is going to trigger anything you have in the constructor. If it's not in the constructor then it can make things easier to test.
I bet you can understand NgRx after watching this video
22:48
Joshua Morony
Рет қаралды 184 М.
I only ever use *these* RxJS operators to code reactively
25:25
Joshua Morony
Рет қаралды 131 М.
规则,在门里生存,出来~死亡
00:33
落魄的王子
Рет қаралды 32 МЛН
ДЕНЬ УЧИТЕЛЯ В ШКОЛЕ
01:00
SIDELNIKOVVV
Рет қаралды 4 МЛН
إخفاء الطعام سرًا تحت الطاولة للتناول لاحقًا 😏🍽️
00:28
حرف إبداعية للمنزل في 5 دقائق
Рет қаралды 77 МЛН
Я сделала самое маленькое в мире мороженое!
00:43
Кушать Хочу
Рет қаралды 4,3 МЛН
Why didn't the Angular team just use RxJS instead of Signals?
8:15
Joshua Morony
Рет қаралды 97 М.
RxJS Scan Operator - How to Manage the State
16:33
Decoded Frontend
Рет қаралды 11 М.
Angular Mistakes #6: 🛑 STOP Overusing Centralized Stores
20:20
Angular University
Рет қаралды 6 М.
What I learned from this crazy RxJS stream in my Angular app
25:31
Joshua Morony
Рет қаралды 21 М.
RxJS in Angular: Terms, Tips, and Patterns
43:01
Deborah Kurata
Рет қаралды 31 М.
State Management in Angular: From Facades to NgRx and back | Cornelia Rauch
51:52
International JavaScript Conference
Рет қаралды 17 М.
How to share your RxJS observables for improved performance
10:24
Joshua Morony
Рет қаралды 24 М.
The easier way to code Angular apps
9:54
Joshua Morony
Рет қаралды 67 М.
规则,在门里生存,出来~死亡
00:33
落魄的王子
Рет қаралды 32 МЛН