Тёмный

I tried to build my dream (simple) state management for Angular 

Joshua Morony
Подписаться 73 тыс.
Просмотров 11 тыс.
50% 1

My Angular course: angularstart.com/
We've talked a lot about this idea of using RxJS and Signals for state management, where RxJS handles data sources and events and Signals handles representing the state.
To make this process and easier and more declarative I've been working with Chau Tran to develop a utility called signalSlice.
signalSlice docs: ngxtension.netlify.app/utilit...
Example implementations of signalSlice:
github.com/joshuamorony/angul...
github.com/joshuamorony/angul...
github.com/joshuamorony/angul...
Get weekly content and tips exclusive to my newsletter: mobirony.ck.page/4a331b9076
Want to build mobile apps with Angular?: ionicstart.com
0:00 Introduction
1:35 Signal Slice
1:54 Creating state
2:09 Selectors
2:24 Sources
2:56 Action Sources
3:49 More declarative?
#angular #rxjs #signals
- More tutorials: modernangular.com
- Follow me on Twitter: / joshuamorony

Опубликовано:

 

31 май 2024

Поделиться:

Ссылка:

Скачать:

Готовим ссылку...

Добавить в:

Мой плейлист
Посмотреть позже
Комментарии : 62   
@JoshuaMorony
@JoshuaMorony 6 месяцев назад
Big thanks to @ChauTran who handled most of the tricky typing/API design issues for this utility, go check out his channel: www.youtube.com/@ChauTran And another big thanks to Alexander Castillo for sending through the first public PR for signalSlice!
@asyncpipe
@asyncpipe 6 месяцев назад
One day we will find the holy grail of state management
@napapt
@napapt 6 месяцев назад
If one day the browser API adopts signals natively then I want to believe it the that
@nomoredarts8918
@nomoredarts8918 6 месяцев назад
Check out Elm language architecture. The holy grail is there
@botondvasvari5758
@botondvasvari5758 6 месяцев назад
svelte
@kubanm3
@kubanm3 6 месяцев назад
This looks really good. And ease of creating component/feature/global state it can give is tempting.
@AaAndz
@AaAndz 6 месяцев назад
Very interesting! I'll definitely use it
@returncode0000
@returncode0000 6 месяцев назад
Pretty impressive!
@omergronich778
@omergronich778 6 месяцев назад
This is dope! Very similar to Mike Pearson's state adapt. Will definitely give it a try!!
@JoshuaMorony
@JoshuaMorony 6 месяцев назад
StateAdapt helped shaped a lot of my thinking around the initial state management approach (without libs) and this utility is basically just an extension of that
@balintcsaszar6831
@balintcsaszar6831 6 месяцев назад
1. the concept is really close to ngrx (signalSlice = reducer, there actions and selectors, I assume ngrx effects can be cloned too, then it is the same with different solution) 2. for me it is a bit too nested, which means, could be less readable 3. Idk the future but currently signals are heavier structures than observables => performance measurements would be interesting 4. thanks for the video 👍interesting
@alandragicevich2421
@alandragicevich2421 6 месяцев назад
I would have thought signals are a lot more efficient than observables.
@JoshuaMorony
@JoshuaMorony 6 месяцев назад
Thanks for the thoughts - yes very similar in fundamental concepts to NgRx, although I would frame it as that both signalSlice and NgRx implement the redux pattern. Nesting is a fair point, could probably do some thing to address this if the indentation is too much (e.g. rather than defining everything inline they could be defined separately: add: actions.add)
@1777bond
@1777bond 6 месяцев назад
VERY NICE
@quattroUnodos
@quattroUnodos 4 месяца назад
1. Anyone incorporate NGRX component-store with signal components? 2. Comparing NGRX Component-store to the solution in this video: component-store already has all the functionality shown in this example plus the elaborated on extension of signal slicing using the built in selectors. 3. Regarding SRP-ish concerns: we use component-store to separate out a lot of this logic from the component and our components rarely do anything except map a view model observable to the template and map template interactions to methods of the component store. Sometimes the component will have basic UI related code, but they are almost completely divorced from service interactions. 4. Is removal of state and system interactions from the component itself, pushing it into component-store (which is very similar to a behavior subject service) a natural step or does it introduce unneeded complexity?
@dangerfox1776
@dangerfox1776 6 месяцев назад
Is the simplicity in creation worth the loss of redux dev tools within NGRX? I find seeing live state, and actions while creating and debugging complex applications invaluble.
@kubanm3
@kubanm3 6 месяцев назад
Maybe they'll add it in the future.
@JoshuaMorony
@JoshuaMorony 6 месяцев назад
I imagine it probably would be possible to support redux dev tools with this approach (it's still essentially the redux pattern), it's something I'd have to look into
@thomasclague595
@thomasclague595 6 месяцев назад
Me & my team currently use your signal based state management approach in our latest app. We previously used NgRx but the one thing I am missing is the redux dev tools integration, this would be a huge step in the right direction for a more widespread adoption, good work! @@JoshuaMorony
@craigritchie8470
@craigritchie8470 6 месяцев назад
A lot of this is making sense to me but I’m having trouble figuring out where to put calls to a Toast service to let the user know an update was successful. Or say after editing and saving an entity I want to change the title in the tab to reflect the entity name change. Where do these things go? Right now I’m placing the code in my subscribes, for example, the save$ Subject action.
@JoshuaMorony
@JoshuaMorony 6 месяцев назад
Generally just with standard signal effects that react to state changes - you can just use the standard effect API but signalSlice does actually currently support an effects config if you want to supply it directly to the signalSlice. I'm also currently working on a PR for "actionEffects" so would love your thoughts on that if you have any: github.com/nartc/ngxtension-platform/pull/154 basically this would allow for defining side effects from streams/actions rather than just changes in state Edit: to clarify, side effects should generally be used very sparingly/only when required (toast is a reasonable use case for a side effect imo and I do the same) - for updating a title for a change in an entity you would probably just want to have that title defined declaratively so it would just automatically update itself
@craigritchie8470
@craigritchie8470 6 месяцев назад
@@JoshuaMorony Comment made in PR.
@trevormontgomery6795
@trevormontgomery6795 6 месяцев назад
Will the course be updated with your new state management technique shown in this video
@JoshuaMorony
@JoshuaMorony 6 месяцев назад
No this is too opinionated I think to have as the approach for the course, I want to keep the course approach vanilla/focus on the fundamentals rather than teach a specific state management library - I might add a small extension to the Advanced State Management module though where I showcase different state management libraries/approaches
@stonecoldcarebear
@stonecoldcarebear 5 месяцев назад
@@JoshuaMorony I'd really appreciate that extension. Course is great by the way 👍
@chaos_monster
@chaos_monster 6 месяцев назад
I struggle to see the benefit of this over the usage of a service with methods for actions and usage of (the most neat and handy addition of) connect
@JoshuaMorony
@JoshuaMorony 6 месяцев назад
For me I would otherwise have actions defined separately as subjects and reducers for those actions/other sources in the constructor (either subscribed manually or with connect), this allows defining those reducers declaratively in the state and also handles creating the actions automatically for you
@chaos_monster
@chaos_monster 6 месяцев назад
@@JoshuaMorony I think there is the key difference in our thinking. I would think about using and for that reason updating the signal in an action method instead of using observables/ subjects by default Edit: to the reducer topic, I would have that in the `connect().with()` as it really fits there. So for that reason an action method would either update the signal or (and yes that is a valid argument) next the subject.
@JoshuaMorony
@JoshuaMorony 6 месяцев назад
@@chaos_monster yes there is a bit of a difference there - for me the main reason for having all actions/events represented by observables/subjects is to keep everything declarative/composable - this way you just trigger the action subject, and anything that needs to react to that can be derived from that action. With callback functions as this mechanism you would need to be imperatively triggering whatever needs to happen when that action is triggered. Not trying to say this is wrong, just not my preference And as for connect.with I agree it's great, not sure if you saw but one of my recent videos is on this. signalSlice is basically just one step further to remove the disconnect between action sources/state/reducers
@rohitkharche7562
@rohitkharche7562 6 месяцев назад
Can you please cover analogjs and give your thoughts about it ?
@JoshuaMorony
@JoshuaMorony 6 месяцев назад
Yes - I've been so keen to try out Analog properly for a long time, and soon I will finally have the time to do it. I'm expecting to create a lot of content around Analog
@botyironcastle
@botyironcastle 5 месяцев назад
wouldn't it be better to use custom events and listen them as a reducer instead of observables and sub?
@manit77
@manit77 5 месяцев назад
Both ends up with the same result. Someone clicks a button and it does something.
@RobertMulderNL
@RobertMulderNL 6 месяцев назад
What do I do when I have an action that posts an update to the server for an item in the state, but between starting the action and completing the update I want to set a loading = true on the item being sent. As far as I can tell you can't update the state in the middle of the action stream(to set the loading flag), only using the resulting item in the action stream
@JoshuaMorony
@JoshuaMorony 6 месяцев назад
This requires using one of the features I didn't cover in this video - essentially you are going to need two sources that react to the same action, but sources can't react to actions created internally by signalSlice. What you need to do is define an external action as a subject, and pass that action into signalSlice (you can see an example of this for my pagination$ action here: github.com/joshuamorony/angularstart-giflist/blob/signalSlice/src/app/shared/data-access/reddit.service.ts). So in your case you would have something like an external update$ action that is passed into signalSlice, and then you would have one source (e.g. updateStarted$) that pipes off of update$ to set the loading state to true as soon as the action is triggered, and another source (e.g. updateCompleted$) that also pipes off of update$ and switchMaps to the request and you can then map this source to handle setting the loading back to false/whatever else you need to do
@RobertMulderNL
@RobertMulderNL 6 месяцев назад
@@JoshuaMorony Thanks for the reply, I'll try to find time to whip up an example and try this out. When you talk about 'pass that action into signalSlice', you mean add it as a property of the 'actionSources' object correct? But then how do you trigger it? By calling service.state.myAction(param)? Or by emitting on the external subject? Also, I've looked at your example, but the pagination subject used as the value of the 'pagination' actionSource, emits either string or null, not a partial of the state. Shouldn't the actionSources be mapped such that the end result they emit is a partial of the state? Finally, if you have a better way of communicating than RU-vid comments, let me know :)
@RobertMulderNL
@RobertMulderNL 6 месяцев назад
Nevermind me, I'm somewhat of an idiot it would appear. With the action stream being an observable whose emissions alter the state, I can ofcourse just make sure the call to the server observable I switch to has a 'startsWith({loading: true})' to change the state as soon as the call is made...
@JoshuaMorony
@JoshuaMorony 6 месяцев назад
@@RobertMulderNL ah yes sorry I responded to your question too hastily, I do the same thing here for a login action: github.com/joshuamorony/angularstart-chat/blob/signalSlice/src/app/auth/login/data-access/login.service.ts - but as for situations where you do need external subjects (i.e. you need your sources to react to actions being triggered) you can indeed trigger it by calling "service.state.myAction(param)" you don't have to do this, you could just next the subject directly, but the idea behind passing the subject to signal slice is so that all of your actions can be available on the state object, rather than having some internal/some external.
@RobertMulderNL
@RobertMulderNL 6 месяцев назад
@@JoshuaMorony thanks again for the quick reply. These external subjects (like the pagination$ in your reddit example) do not have a direct way of updating the state like other actions do, correct? If you do want them to somehow manipulate the state they must at some point lead back to a source right?
@Augustinasas
@Augustinasas 6 месяцев назад
I mean I really like this as an experiment to deepen my knowledge about redux pattern but is there something fundamentally wrong with NgRx? I feel more like using well established library that has tons of tutorials to pass for my dev team, than to use a new implementation of redux pattern without hearing what the NgRx (or NgXS, akita) was lacking. I fail to understand where using this library would be beneficial instead of using traditional redux libraries. Are there specific use cases?
@JoshuaMorony
@JoshuaMorony 6 месяцев назад
This hasn't been developed in opposition to any other library, the motivation for this was basically: 1) Signals are new and are going to impact the way we manage state 2) I landed on an approach I like for declarative Signals + RxJS state management where we have data sources/events represented by observables which are at some point used to update a state signal 3) There is boilerplate involved with this approach, so I want a utility that essentially keeps the same idea but removes as much boilerplate as possible and that's what signalSlice is It's essentially a single function that can be used to create a "slice" of declarative state using RxJS + Signals, it is much more a simple state management utility than a more full featured state management library.
@tolstoievski4926
@tolstoievski4926 6 месяцев назад
is takeUntilDestroyed really necessary for http requests ?
@JoshuaMorony
@JoshuaMorony 6 месяцев назад
I will always unsubscribe as a rule even if in a particular situation it isn't technically required. But in the case of http requests yes it is still mostly necessary anyway, consequences might be rarer but you can run into trouble with situations where a component/service is destroyed but an HTTP request hasn't finished yet and without some kind of unsubscribe strategy it will still complete which can cause problems
@tolstoievski4926
@tolstoievski4926 6 месяцев назад
@@JoshuaMorony problems like a disconnection between the state of the app and the ui ?
@jhadesdev9576
@jhadesdev9576 6 месяцев назад
Thank you for sharing, but I cannot see how I could realistically train my team to understand this or even maintain code written in this way. Why not just use Signals instead of RxJs for the vast majority of use cases, and use RxJs only when and if we really need to? I don't know if you heard but the Angular team has announced that they will make RxJs optional in future releases.
@JoshuaMorony
@JoshuaMorony 6 месяцев назад
This is really more intended for people who are using or want to use a declarative style of coding in Angular - this state management utility is a natural/easy extension in that context, but outside of that context it is a big paradigm shift and I wouldn't expect people to use this utility in that case Edit: Forgot to address the signals vs RxJS question - a lot of my videos recently have talked about this but to put it briefly you will still need RxJS (or some equivalent) to write code declaratively even with signals
@jhadesdev9576
@jhadesdev9576 6 месяцев назад
​@@JoshuaMorony I also went into the RxJs rabbit hole myself, and for frontend development, I think it's not worth it the whole declarative style thing; This idea that everything in an application is a stream, including something as simple clicking a button, it's just not necessary. For me it's just over-abstraction and over-engineering, it's just not good design. The code of my app had far more bugs caused by my team misunderstanding how RxJS works. It's just a very advanced concept that developers struggle with, even senior ones. I've switched my team to async/await code which is widely adopted everywhere for years outside the Angular ecosystem, and we are way more productive this way. We don't need RxJs for doing HTTP, plain async/await is a way better fit, and it's even recommended by the Angular team in their latest beginner tutorial on RU-vid. These days we only use RxJs if absolutely necessary, and the code just feels way better this way.
@TheSysmat
@TheSysmat 6 месяцев назад
Doc for slice signal is confusing
@JoshuaMorony
@JoshuaMorony 6 месяцев назад
Will definitely improve this - the docs atm have basically been added piece meal as new features were added
@StephenMoreira
@StephenMoreira 6 месяцев назад
Personally, I'm okay with the imperative portions.
@JoshuaMorony
@JoshuaMorony 6 месяцев назад
Me too, I think the full vanilla approach is fine and I think the sacrifice in "declarative-ness" there has very little impact
@bric305
@bric305 6 месяцев назад
Agreed, but it is interesting to see how close you can get to full declarative!
@Maxzilla60
@Maxzilla60 6 месяцев назад
I'm still not fully convinced the sources need to be Subjects? Couldn't you just provide and call a method instead of "next'ing" a Subject property? 🤔 So it'd be "checkListService.add(...)" instead of "checkListService.add$.next(...)".
@JoshuaMorony
@JoshuaMorony 6 месяцев назад
You could but it leads to a different style/more imperative code - if it's a method then that method needs to imperatively trigger whatever needs to happen when that action is triggered, whereas with the subject approach you are essentially just broadcasting that the action happened and whatever needs to react to it can do so declaratively
Далее
I used Angular's signals to build an actual app
7:36
Learn Angular Signals - The Future of State Management
10:02
The Worlds Most Powerfull Batteries !
00:48
Просмотров 7 млн
The mindset you need for a DECLARATIVE code refactor
7:56
This Library Makes State Management So Much Easier
12:07
My go to way to manage state in Angular applications
9:43
My NEW default for state management in Angular
6:21
Просмотров 29 тыс.