[Watch This Space] Angular Reactivity with Signals · Discussion #49090 · angular...
source link: https://github.com/angular/angular/discussions/49090
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
tl;dr: we've begun some prototyping work around adding signals as a reactive primitive in Angular, in advance of a formal Request For Comments (RFC) which we plan to open soon. Prototyping early and in the open aligns with our team values and allows us to get the most out of an RFC. If you've seen our talk from ng-conf 2022, Angular: A Design Review 10 Years Later, you know we've been thinking long and hard about some fundamental design decisions of the framework. Last year, we kicked off a long-term research project with an ambitious goal: to embrace fine-grained reactivity in the core of the framework. In a fine-grained reactive web framework, components track which parts of the application's data model they depend on, and are only synchronized with the UI when that model changes. This is fundamentally different from how Angular works today, where it uses zone.js to trigger global top-down change detection for the whole application. We believe adding built-in reactivity to Angular unlocks many new capabilities, including:
Changing the reactivity model of an established framework like Angular is a significant project, with numerous challenges. Our plan for this project is broken out into multiple phases:
Over the last few months, we've progressed through the first and second stages of this project, and have converged on a design based on the well-known reactive primitive of signals. During our experimentation we felt that this design demonstrated the strongest alignment with our overall goals. Signals are not a new idea in the framework space - Preact, Solid, and Vue all employ some version of this concept to great success. We've taken a lot of inspiration from these and other reactive frameworks, and we are especially grateful to Ryan Carniato of SolidJS for his willingness to share his expertise and experience in many conversations over the last year. That said, requirements across frameworks differ widely, and we've designed our version of signals to both meet Angular's specific needs and as well as take full advantage of Angular's unique strengths. Even though it's still in the prototype stage, there are a few aspects of our design which we're particularly proud of:
We've begun prototyping this design and will be integrating it into Angular over the next few months. We're committed to our open source spirit and plan to conduct these prototyping efforts in the open. This prototyping is essential to proving that our design for signals in Angular is viable and allows us to progress to a community RFC. The RFC will cover the rationale for using signals and the detailed design of various parts (our implementation, integration with RxJS, and other topics related to this effort). We strongly believe that adding built-in reactivity to Angular is in the long term best interest of the framework and its users, and look forward to sharing more information about this project in the upcoming RFC. When will the RFC be?Sometime later this year, depending on how smoothly the prototyping efforts progress. Why signals as the reactive primitive?This is a great question, and one which will be thoroughly discussed in the upcoming RFC. In short, signals have many of the properties we identified as desirable in a reactivity system designed for Angular, including:
Why are you committing code before the RFC?There are a few reasons why we've chosen to begin prototyping before opening an RFC:
|
Replies: 33 comments · 139 replies
I advise you to take a look at the following signal implementations: artalar/act, nanostores/nanostores. |
Amazing. Can't wait to see the prototype |
Here is the prototype of the signals lib: #49091 |
So basically, it is the Reactivity API from Vue with different function names? In Vue, it is possible to just use the property name, which makes it easier. |
Here are a few libraries you may find interesting for the prototyping phase: https://github.com/damianstasik/awesome-reactivity |
I hope we'll one day make the list! |
I would also add Effector to the list https://github.com/effector/effector |
I do not like dirty functions (functions with the internal state, AKA “hooks”), I think that functions should be pure and for keeping the state we have class instances. So, the fact the “hooks plague” is corrupting Angular is bad news for me, but if it will help us to get rid of zone.js - amazing. Because zone.js is much worse. |
I would argue "the best of two worlds". There is a simplicity mirage when people see signals from far away, but when they get near, they understand how ugly and bad it is. For example, having two types of "for" is a bad design, no matter how you look at it. Having two types of "for" is a side effect of fine-grained reactivity. Angular will eventually need such bad designs as it is baked into fine-grained reactivity. For these kinds of designs, even it's impossible to write lint to catch wrong usages. It is a nightmare for big projects. Or sometimes you need to manage your dom rendering changes yourself instead of the framework to take care of that. https://www.solidjs.com/docs/latest/api#createrendereffect And solid can cause max call stack limit if a project is big enough. Just imagine something like a role or permission that is used in every part of the application change. https://stackoverflow.com/questions/7826992/browser-javascript-stack-size-limit For every effect you keep adding, your memory usage will increase multiplied by the number of signals used inside that effect. Bcs every signal keeps track of its effect and its usage reference. That's a big no for low-powered devices. Clean-up of the lost references effects and signal usages also is another story. If someone asks you if having a framework that keeps adding and removing to arrays on every function usage in your application, and it does it multiples by the number of signals in your application, is it a good framework? What would be your answer? And I want to remind you that every line of your template that uses a signal is an effect too! Rx-angular solved the issue of the complexity of rxjs. I don't understand why we can't build on top of that! For anyone who thinks the signal is a good design choice, I suggest trying to recreate some part of their application with it. |
But rather than being forced to use rxjs you have a simpler option and 3rd party libs that do it much. Better. |
Getting rid of Zone.js is a good direction but Signals looks like (another) revolution in the Angular world. |
Yeah, it would be interesting to know what other options were studied. And Rx Angular or NgRx were not good enough in comparison to signals. |
+1 for MobX decorators and rx-angular approach, rather than yet another "revolution" in Angular. |
So basically after 7 years of development you figured out that RxJS is "doesn't fit all the needs" huh? |
I do need real HMR, and anybody who does more or less complex enterprise-grade application does. It was reloading whole your app without refreshing the browser page, nothing more. It's not HMR at all, in any sense. Just read through that issue, no need to continue an offtopic discussion here. |
I was actually thinking along the lines of what @dgp1130 said I think after esbuild hmr will come into focus more, so it's not like the team is doing nothing, they are at least making progress toward it. You're a developer too, you understand, these things take time and you can't just choose what you want to work on whenever, I'm sure they want to give you proper hmr support, why wouldn't they want it? So there must be a reason and I don't think being toxic about it helps, a lot of things that we are getting now in Angular have been asked for years BUT WE ARE STARTING TO GET THEM, your hmr time will come, just support what's being done right now. |
That's what happen for years now. They have "other priorities" like Ivy and now... what they call "Signals". |
You just illustrated why signals are great, not only do you have to use those extra operators to achieve the same thing, you have to learn them as a new developer and also be aware of any gotcha that can happen, also then you expect Angular to create a custom method just for that, why not use something the js ecosystem is adopting , if you want to use RXJS still and know how to no problem but you can see it already makes Angular simpler because if you get a new developer instead of telling them use all those operators, just create a signal, and now if they want to use solid or something else the knowledge is re-usable in much less time. |
Yes I want to use RxJS and I want Angular to improve their integration with RxJS instead of making up new things, that could turn out to be a failure in another 7 years. Another operator needed? No problem, make it. But not a hook-like "something else". |
Angular is the best framework |
RxJS is synchronous as long as there's nothing async present in the pipeline like a
But it's easy to get something async into a pipeline that will the break all previous assumptions about if it's sync or async |
Not at all. There's a difference between an exchange of ideas, and "arguing". You're just here arguing, with a "I hate this, you suck" energy. That's not constructive. |
Ok, let's think how you could replace a single signal with rxjs implementation. For each signal you'll need to have a separate Now you need some computed from those "signal" observables. Ok, mapping them and also piping to And also don't forget to add dozens of |
Just like it's done for EventEmitters. They are part of Angular and aware of Component lifecycle, there's no need to subscribe or unsubscribe, and still it's based on RxJS. Right? I'm not saying "don't hide the implementation logic", I'm saying that maybe - just maybe - Angular doesn't need another one reactive solution apart from RxJS that's already there.
|
Well, it may be a bad news for some, but when you start using RxJS somewhere in your app, it is much easier to use it everywhere to avoid what you've discribed. Add a declarative pattern to it and (after you get used to it), in my personal opinion, it will become incredibly confortable to use. |
Exciting development. Thanks for all the work and for the team's transparency along the way. |
I hope it will not have too much impact on the existing development model. |
Here's how it's gonna be, remember my words:
Hopefully HMR is done by that time. |
Awesome! |
@menosprezzi The concepts What signals really open up in the feature is an alternative to zoneJs. I'm really looking forward t that future! |
@SanderElias nice! But I mean that implementing InteropObservable interface you can use the signal directly in your rxjs pipes if you need. For instance, lets say that angular changes the @input to wrap values into a signal, you can still use it with the rxjs's reactive utils if you need:
This will ease the migration between both! |
I think signalFromObservable() is really essential to have in place when this lands. It also has to automatically handle the subscription. If this gets done right it will be a really nice solution. |
wou, what @menosprezzi said is interesting |
I kinda want to stress-test this RFC with some questions that the Angular team may want to consider:
Those are just some questions I can think of at the moment, and I'll update this comment when I think of more questions. I am sorry being a pessimist with this RFC, and I am not trying to shoot this RFC down; however, RxJS is a critical part of Angular, and replacing it will cause millions of websites to break if this RFC is not handled carefully. If this RFC goes through, I would suggest creating an extended LTS version or a compatibility mode, so websites have a good window of time to migrate before the pre-RFC versions sunset. |
They mentioned it 2 times:
I think it means that they are taking care of it and you don't need to worry about your existing code, relying on RxJS. Also, this tweet might be helpful
|
@e-oz Sorry... |
No @IRod22 you shouldn't be sorry, because you are right: there will never be "magic", even though they claim there is, like with NgUpgrade. Any interop will help us only partially, but there definitely will be a need to worry about existing code. |
Thank Angular team! I have been watching the progress of optional zone for many months. It is fantastic to adopt signal fine-grained reactivity to Angular core. Will the signal be able to run outside of component like Solidjs? If it does, that will be super helpful to reuse/organize many common logics. |
@BruceWeng Yes, they will be available wherever you want to use them. You can use them in services and functions and wherever else you might need a reactive primitive. |
wow congratulations |
Should be a great addition! I guess it might change how we look at state management. Is there any thought how signals can enhance state management? Or maybe even a native angular solution? |
Really excited to see how the Angular team implements and builds around Signals. I think this is a good step towards dealing with Zone.js just as Standalone Components do with Modules. From an implementation standpoint, what benefit does a BehaviorSubject provide over a Signal? Are there specific cases where I’d want to choose a BS over a Signal? |
the main point is you don't need to handle subsription/unsubscription with signal compare to Rxjs Subject |
Thanks! Came here to ask the same question! Not needing to subscribe/unsubscribe would be awesome. |
@ntorrey yeah imagine not having to do |
That’s sort of my point. What benefit would a BehaviorSubject provide if a Signal can be easily transformed into an Observable? Seems like it’d save people from the private BehaviorSubject + getter/setter pattern I’ve seen in quite a few codebases. |
@Cjameek you'd still want to have Subjects to handle streams of events or asynchronous events. Eg: a search input with debounce.
|
I'd like to put another problem in discussion: How about the learning curve of Angular? |
why signals if we have already reactivty via Rxjs? |
One important question. What about all rxjs stuff that is introduced in simplest examples like |
Rxjs is awesome, I use it also in Vue a solidjs, mapping rxjs observables to their signals. And also, ecmascript is considering including native observables, they are already in stage 1. I think with observables is going to happen like with promises 10 years ago. Promises only existed in jQuery and libraries and finally were natively implemented in js. |
I think this is more of an internal implementation for updating the DOM. Right now every change detection cycle requires a scan of all the data model to see if something needs updating. This is the zone.js model; it encapsulates all the javascript tasks and tells the framework when the tasks are done, then the data model scan. It is expensive and has quite a few gnarly issues that we have to work around. The signal implementation would, if I understand it correctly, have each property of the data model subscribed to by the dom manipulation system to know when something changes. From the user side, these primitives can be useful for simple data manipulation and update situations, which is most of the time. For more complex data structures and data flows full of asynchronous events, rxjs has more tools for dealing with them, along with the complexity and learning curve. Hard problems require powerful tools, simple problems are best with simpler tools. |
I think actually the learning curve will be simplified probably the end goal will be that you don't have to learn rxjs to use Angular but you can use it if you want and are willing to learn. |
Would this be needed at all if Angular would handle change detection like Svelte does? Can't this whole thing be done fully in the compiler so no user-code would then needed to migrate as long as it's fully As for signals, as long as I can pipe out of a signal like with observables and has the familiar Implementation wise I see this this is a tradeoff of code shipped and performance. And since rxjs is already shipped, building a Signal out of rxjs building blocks is practically free. And then it would really be like EventEmitter, as subject that integrates with the component lifecycle and unsubscribes when no longer needed (and then some, like distinctUntilChanged etc) And performance wise, usually a tailor-made solution is more performant but I think a thorough benchmark should be done comparing these two Signal implementations. |
Exactly. If there's an EventEmitter -- still based on RxJS -- why to add another "reactive primitive"? It also unsubscribes and automatizes things for you.
Also from conceptual and learning point of view.
|
As this thread seems to be as much about opinions on pros/cons for exploring signals versus rxjs/rxangular/mobx: My 2 cents: We have been developing an application over the last years that heavily relies on reactivity. However, working with RxJS does have its pitfalls, all of the ones have been summed up somewhere in this RFC. If the Angular team thinks that signals potentially would do that, great. As such: worst case: effort being spent by the team towards signals and it doesn't work out. No problem for us, we just continue to use RxJS. Long story short: I'm all for it. |
Or, the team could spend energy on improving e.g. debugging of RxJS via e.g. some kind of panel in Angualr DevTools. Or building up new operators and abstractions based on RxJS. In other words, improving the RxJS integration. |
That's too optimistic. I can't remember a single "RFC" where team would change their decision. If they published something - it's already decided. The only useful thing we can do here is to remind them what cases they didn't test. |
Improving on RxJS seems like a good alternative option. |
I just tested Signal, it's easy to use but I don't see the difference compared to BehaviorSubject, except for other improvements (zone.js, Change Detection), so why was it added? |
Which is currently a much "weaker" version of rxjs based effects for async stuff. So I guess it should somehow play together |
What I will also like to see is how would it play with many state managements concept of effect functions. Many effects are not based on value change but based on actual DOM event and only using current value of the state (or selector). Currently there are many problems like the diamond problem or batching problem which can be solved with denouncing (making it async) which as a result make effects using selectors more complicated. It seems signals can solve those problems entirely if they are lazy, batched and always updated. |
Yep, this is definitively a nice property of the signals approach. Especially with the proposed implementation where signals / computed are lazy by default and effects are scheduled to run in a separate JS stack frame. |
The only thing I am missing is how the signal's effect (sync regular code) can be "merged" with async rxjs code requiring most updated signal value. Currently in places an effect function requires a new microtask to access denounced selectors values a chain of those effects will run each in its own microtask. Will signals be able to make it sync? Or the same concept but easier to handle? I kind of can't wrap my hand around it - as signals and computed are sync while signal's effects are kind of async by nature if I understand correctly. |
Probably use of custom scheduler, but this should partially be handled by signal.toObservable() or something like this maybe? |
The Angular team is working on adding a fine-grained reactivity system to the framework, which will allow components to track which parts of the application's data model they depend on and be synchronized with the UI only when that model changes. This is different from how Angular works currently, where it triggers global top-down change detection for the whole application. The team has been prototyping the design using signals as a reactive primitive, and plans to open a Request For Comments (RFC) soon. The goal is to unlock many new capabilities and simplify many framework concepts, with a viable path towards writing fully zoneless applications. The team plans to collaborate with the community to bring the entire Angular ecosystem into a reactive future. |
This looks like ChatGPT |
Yes, always takes expert advice! :) |
Should Angular move to Signals? ChatGPT: Assuming you're referring to signals in a broader sense, such as a system of communicating between components or modules within an application, my answer would depend on the specifics of the situation. Angular is a popular web application framework that provides a lot of built-in functionality for building complex, scalable applications. It uses a component-based architecture, which allows you to break down your application into smaller, reusable pieces. Components can communicate with each other using a variety of mechanisms, including input and output properties, services, and observables. If you're currently using Angular and are considering switching to a different approach for component communication, it's important to carefully evaluate the pros and cons of any alternative approach. Signals may be a valid option in some cases, but they may not be the best choice for every situation. Ultimately, the decision of whether to use signals or any other approach for component communication depends on your specific needs and goals for your application. If you're unsure which approach is best for your situation, it may be helpful to do some research and/or consult with other developers who have experience with similar projects._ |
ChatGPT results depends upon user's input. Dump input, Dump answer. Smart input, smart answer. |
Please consider exposing this API "only" through Decorators!After seeing the proposed reactive API and tryouts from people here and there I believe using this API with functions like signal(), computed(), etc. would make Angular a worse copy of Vue composition api or Solidjs. But you have the chance to provide a better one with decorators. Here is why. Looking at this from purely DX perspective current Angular is already reactive enough. When we want to update an element we just set the property of the component class and thats it. I know you can keep it that way by using decorators. Vue or Solid cannot do that simply because they don't have class component to utilize decorators and reactive primitives needs a way to be subscribed for changes such as
In Vue.js read/write (subscription/notify) is done by accessing or mutating the value property of reactive primitive and In Solid.js same principle is done by calling the signal value and the setter respectively. For angular we don't need to define any extra getter/setter or value property for a reactive primitive since we work with classes and we have "this" to access any property for read/write. Here is an example of a possible reactive service via decorators. (This syntax applies for components too)
And when we want to consume this service we simply access or mutate it as normal.
instead of
My final concern about exposing this reactivity API through functions is that it does not force you to use classes and can be written anywhere in your codebase. This may sound like a good idea to many developers but it's not. After a while we will start seeing projects ditching classes, services and DI completely because it will be tempting to write less code at first without anticipating the complexity as it grows. Exposing the API only by decorators will enfoce the current Angular's class based architecture which makes it scale better than any other framework out there. So my question is: have you already considered how to ship this API? Or is it too early before the actual RFC? |
Man I just want good future for Angular and us, the developers |
So do I, and so does everyone here. And each person may have a different perspective on what that means to them. And that's ok. Each person's perspective is valid, but you've been jumping down people's throats if they have an opinion you don't agree with. Just be civil, and we'll work together towards a brighter future. |
What did I say wrong? Re-read my comment. What's invalid there? Don't take it personal, please, it's not about you. Allow people to have their own opinion. P.S. I'm sorry if I hurt you though |
Not only does that misrepresent what I said (I said more functional, not functional everything) but it's also basically saying get lost and use another framework if you want it x way. That's hostile and not very inclusive of others' ideas. Whether you meant it that way or not. But to your point on decorators being added to the ecmascript spec, they are, and that's great, but they're more limited than what TS' prior implementation was (e.g. using decorators in function params). And that's sort of what I meant by limiting how you can use signals in that way may be a bad trade-off. |
First, I understand your point. But I also see what makes Solid so successful which is the focus on primitives. Angular also needs these primitives and once it's exposed to developers, we can build on top of it. Functions just compose better. And the last thing, I would miss creating helper functions together with inject fn, if not exposed. Just my current view. |
I hope that the entire JS execution environment can have reactivity, like this. test demo |
What framework is this??? |
@tayambamwanza This is a reactive JS execution environment built with dependency compilation-time semantic analysis and runtime Proxies. |
|
@nin-jin In a reactive JS & HTML hybrid language execution environment, it can be written like this.
|
I hope that the development process of frontend frameworks does not require more hacks, and the ultimate goal of frameworks is to enable developers to write UI interactions just like writing JS logic. |
We have just gone through a very long process of upgrading to Angular 15 from Angular 14 which tooks us over 1.5 months to complete due to all the Angular material changes. We have a VERY large project that we have been developing since Angular 2.0 Alpha with a massive undertaking and many developers involved. We just hope and pray that whatever path the Angular team chooses, that it is 100% backwards compatible as we want to continue and progress forward with Angular versions. Or, have a cli-upgrade migration, which honestly may be like voodoo magic as it sounds like this would be a challenge. In any case, PLEASE make future Angular compatible with our current projects which is rxjs heavy, fully ng opinionated with ngrx etc; tldr; we followed all of Angular's team best practices over the past decade, please don't make us drop it all for the latest bells and whistles as we are perfectly happy with how Angular works today, it ROCKS! |
feels good that those problems are finally getting addressed. I kind of have already got used to using Subjects, ReplaySubject and BehaviorSubjects. However I understand the point the Angular Team has on using a more simplified approach and having the option to opt out of RxJS. Here are my take aways and problems I had using RxJS so far and what might be relevant for Signals. When e.g. we use inputs you would have now to have a seperate signal and then set it? At least thats the way I see it from the first glance. This is simular to the RxJS problem which made us spawn always 1 inptu and 1 Subject tolding that input. However order of execution did matter and I'm not sure how well the effect addresses those things cause so far if I have a variable a$ and b$ as inputs if they are in the HTML written like <component [a]="1" [b]="2" /> we had to do thigns onInit cause we needed both to be set and only after that we could do some computation and react to changes. This is a problem which will even occur if we use OnInit but at least at that point in time you should have both observables. Now I'm wondering how those things would work with Signals. I find it odd that you have counter.set(0) but when you wnat the value you do counter(), why then not make it so that you do counter.get() or counter.get or counter.value. Still The 'you will have to unlearn' things is definitly true and I don't wanna be a breaker but I would like to rais the concern that his is still pretty vage and questonable how well it will work. Definitly must be experimented with! What I would like to conclude this comment is that RxJS isn't working in all scenarios as well mainly due to the fact that things will execute one after the other syncronously. You could delay (macrotask) the execution ... what I would like to see is how signals are going to address such scenarios -> maybe this is the Push/Pull Algorithm. |
I create a simple application with angular material, I used Signal to control the dynamic display of a progress bar when there are ongoing HTTP calls, and I also used it to display the results of an HTTP call. I mocked the backend and used the delay operator to simulate the delay of an HTTP response, I find that using Signal simplifies works a lot since there's no need to subscribe and unsubscribe, or use "next" to notify subscribers, etc. This is in contrast to using BehaviorSubject. You can find my example here : https://stackblitz.com/edit/angular-cfjezb |
After some thought I believe this feature can make a great state management. Combining it with ngrx component store idea we can create a store service or function (local and global) easily (a very simplified version of course):
Class based approach:
I think there are two kind of effects:
|
Yes, I was looking at some examples and, I'm slowly convincing myself to the Signals too :) |
Another thing worth mentioning is what's the difference between:
And why should we use one over the other and when |
Good question. And also do changes to the props of state objects trigger the signal updates. I guess if it's going through the |
@Harpush This video can summarize the two cases you mention https://www.youtube.com/watch?v=GEu8hc3RKpw The second approach is more appropriate for a State Management since each "property" of the State object can be referred to as a "Slice". Updating a Slice shouldn't signal (no pun intended) the other Slices |
I think this requires real thought. On the surface it seems like a no question that option 2 is better. But if try and think of the actual usage I am not so sure. A simple example:
In both case Now for a more extreme scenario. I have entities in store bound to virtual scroll in UI. You can add entities, remove and update properties inside. Lets take addition of 1000 entities each with 10 properties inside. The UI will render only 10 of them due to virtual scroll. Now I am not sure which way is better and if there is one correct answer to begin with. |
I just remembered after signals are implemented and zone.js becomes optional, that means Native Async Await right? |
I'm pretty sure, yes. |
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK