I changed my mind. Angular needs a reactive primitive
Mike Pearson

Mike Pearson @mfp22

About: Interested in physics, software engineering and deep learning.

Location:
Utah
Joined:
May 5, 2018

I changed my mind. Angular needs a reactive primitive

Publish Date: Dec 7 '22
124 63

YouTube

Angular developers have waited 7 years for better integration with RxJS, but this doesn't seem to be happening. Instead, the Angular team wants its own reactive primitive that can't even handle asynchronous reactivity.

This made me angry at first, but after a lot of thinking and talking with other developers, I now believe that a reactive primitive could provide an overall better developer experience than just better RxJS support, even for the most diehard RxJS fans.

  1. Better promises?
  2. A split in the Angular community
  3. Rejecting vs outgrowing NgRx
  4. Angular is not reactive enough
  5. You turned them against me!
  6. Ryan Carniato
  7. Oh yeah, RxJS actually sucks at that
  8. Selectors
  9. Colocation
  10. SolidJS signal syntax is awesome
  11. What I want
  12. RxJS compatibility is still necessary
  13. Summary and conclusion

Better promises?

Most Angular developers didn't even know about RxJS until Angular made them learn it for some core Angular APIs.

At first, most of us thought observables were just a nicer version of promises, since they could do everything promises could do, but also return multiple values over time. So we thought we would just get HTTP data like http.get(...).subscribe(data => this.data = data), and we could even handle websocket data the same way, but that would be the extent of RxJS's benefits. I think the Angular team thought of observables this way too.

But the ability to represent long-lived sources of data turned out to be far more than a slight improvement over promises. Observables enable functional reactive programming (FRP), where asynchronous code is defined declaratively. This is a huge deal. FRP can entirely eliminate race conditions and inconsistent state, improve code organization, reduce page load times, simplify state management and make naming easier. My last article explains all of this.

A split in the Angular community

But FRP requires adopting a different mindset in order to take advantage of these benefits. This is known as "thinking reactively." For most Angular developers, the opportunity to explore this mindset came with their first interactions with NgRx/Store.

Rob Wormald created NgRx in 2016 as a go-to state management library for Angular by combining Redux and RxJS. This seemed natural, because Redux was very popular in the React community, and the Redux store already came with a subscribe method, just like observables. It basically already was an observable waiting to be implemented with RxJS.

NgRx sounds really cool and powerful. It's probably really easy to use. Oh wait, how do you access current state? You can't just this.store.currentState?

Nope.

And what's more, there were no plans to add this. And there weren't even plans to plan on adding it either.

This turned out to be the result of some kind of RxJS doctrine. After further exploration, we encountered bizarre advice like "don't unsubscribe", and "don't subscribe". Can you imagine people telling you to not use .then with promises? But in RxJS, we're supposed to use withLatestFrom, takeUntil and Angular's async pipe instead. And if we use the async pipe, supposedly our apps can be more performant.

This was a fork in the road for Angular developers: Do I have something to learn, or is RxJS stupid because I can't do the first thing that came to my mind?

Fork in the road meme

Rejecting vs outgrowing NgRx

Soon after NgRx introduced more RxJS into Angular apps, alternatives started popping up that appealed to developers who didn't want to learn how to think reactively, such as NGXS and Akita.

The split in the Angular community widened as other developers took RxJS and ran with it. I remember listening to a podcast where Rob Wormald (creator of NgRx and member of the Angular team) suggested that the future of Angular would be zoneless with RxJS streams stretching all the way from event sources down to the template.

This was very exciting to me. I imagined we'd eventually have precise updates fed directly into the DOM by RxJS streams, with no need for change detection at all. This would supercharge Angular performance, which was already starting to be on par with React. I hoped that this incredible performance boost would be enough enticement for more and more Angular developers to learn how to think reactively, which would then bring the other benefits of reactivity to more and more Angular codebases: No more race conditions or inconsistent state, improved code organization, reduced page load times, simpler state management and better function names.

But this future seemed a long time away, because I kept having to fight both NgRx and Angular when writing reactive code.

For example, if you had to hit 3 services in series to aggregate data for a page, you could do this with RxJS:

data1$ = this.http.get(...);

data2$ = this.data1$.pipe(switchMap(data1 => this.http.get(...));

data3$ = this.data2$.pipe(switchMap(data2 => this.http.get(...));
Enter fullscreen mode Exit fullscreen mode

The benefit of this is that each data source is declarative, so it stands on its own, agnostic to how it may be used to define other state or features. This is extremely flexible, and has all the benefits of FRP I've already mentioned twice.

But if you want to put this data in NgRx/Store, the recommended solution is not very reactive, so it doesn't come with the full benefits of FRP. I ultimately came up with a way to wrap the NgRx API (dispatch & select) inside RxJS so I could structure my code exactly the same way I could with pure RxJS, and here is how it compared to the recommended pattern with NgRx/Effects:

NgRx/Effects vs RxJS

I used this RxJS-first approach to rewrite a feature that was using effects heavily and reduced code by 25+% and the page load + render time by 90+%.

It took pro-reactivity Angular devs longer to outgrow NgRx than it took anti-reactivity devs to reject it. But we now have some RxJS-first libaries like RxAngular and StateAdapt, which are both state management libraries that enable maximum reactivity in Angular.

So, although both NgRx and Angular introduced developers to RxJS, they were both designed in ways that made full reactivity difficult. I mentioned one issue with NgRx, but Angular had a lot more.

Angular is not reactive enough

It is obvious that RxJS was sort of an afterthought in the design of Angular. It was used to represent event streams, such as component outputs. But it was also used for route parameters, which are states changing over time. But then component inputs, which are also states that change over time, were not represented as observables. RxJS in Angular is basically a really inconsistent experience.

When I hear some Angular developers complain about how cumbersome it is to use RxJS in Angular, I can actually empathize with them. But they should be blaming Angular, not RxJS. Some things that take 4 lines of code with RxJS + Angular only take a single character with RxJS + Svelte. Angular is the only major framework for which most component libraries require dialogs to be opened imperatively, which means the async pipe can't be used, requiring manual subscription management instead. Which is itself much easier in other frameworks.

I could go into a lot more detail, and I have before, but the main idea is this: Even after all the wrapper components and utilities I can create, I still can't fix Angular's core APIs.

You turned them against me!

I have waited a long time for Angular to improve its integration with RxJS. This issue, which was one of the all-time most upvoted Angular issues, was created in December 2015! The first hope it would be worked on was when the Ivy compiler was finally finished in 2019, but after another 2 years of relative silence, the issue was closed entirely! The reason? The Angular team said, "Turning inputs into Observables would more tightly couple Angular with RxJS, and we don't want to further couple with RxJS."

What???

The last comment on that issue before it was closed was by Minko Gechev, who started by reiterating the community split over RxJS: "As we've discussed in the past, the community is very split when it comes to using less or more RxJS with Angular." At the end of the comment he said, "We will share our plans for more ergonomic RxJS APIs when we prioritize that project." For someone who had already waited for 5 years for better Angular APIs, this was very frustrating, as he gave no timeframe at all. Not only that, but the primary reason given was that many Angular developers dislike RxJS, and I strongly believe that the primary reason for this is Angular's obnoxious integration with RxJS.

RxJS turned developers against Angular meme

Then I saw that a member of the Angular team was exploring a different reactive primitive altogether. If Angular developers don't like reactivity, why would they prefer another reactive primitive over RxJS? If they don't like Angular's integration with RxJS, how would using a different reactive primitive help at all? None of it made sense to me.

Ryan Carniato

Another thing that has been bothering me has been Ryan Carniato's insistence that RxJS isn't fine-grained reactivity. I know that RxJS can be used to update the DOM in fine-grained ways, and it turns out Ryan knows it too, because he built a previous version of SolidJS with RxJS. I've been pestering him in the comment section of his YouTube streams for a few weeks now, and he finally gave me an explanation that caused something inside my head to click.

Ryan told me that the reason he calls RxJS "course-grained" reactivity is because, while you technically can perform fine-grained updates with it, people tend to combineLatest with streams instead. Is it fair to say that RxJS isn't fine-grained because people tend not to use it in fine-grained ways? I don't think so, but Ryan's main point was actually interesting. He caused me to make a mental connection that I had never made before.

Oh yeah, RxJS actually sucks at that

When I first used NgRx, I wanted to use RxJS for everything, so I relied heavily on the map operator for derived state. But nowadays, derived state is completely implemented with selectors in pretty much all NgRx projects. So, whereas modern NgRx will combine state from multiple reducers like this:

const selectItems = createSelector(state => state.items);
const selectFilters = createSelector(state => state.filters);

const selectFilteredItems = createSelector(
  selectItems,
  selectFilters,
  (items, filters) => items.filter(filters),
);
Enter fullscreen mode Exit fullscreen mode

Originally I did it like this:

items$ = this.store.select(state => state.items);
filters$ = this.store.select(state => state.filters);

filteredItems$ = combineLatest(
  this.items$,
  this.filters$,
  ([items, filters]) => items.filter(filters),
);
Enter fullscreen mode Exit fullscreen mode

I was pretty happy with this RxJS approach, until my team lead put a console log in the filter function and saw that it was being run 28 times and asked me why. I basically told him, "I have no idea, I swear FPR makes apps more performant."

My first idea was to use distinctUntilChanged. That reduced some of the reruns.

Then I realized that every single observable that chained off of filteredItems$ caused the filter function to run again. The solution? shareReplay(), except actually publishReplay(), refCount() because of some weird RxJS issue. That also reduced some of the reruns.

Then I realized that whenever both items and filters were changed at the same time, the combineLatest would run twice, once per input observable. This was inefficient, but also caused errors in some states, because it was annoying to handle the intermediate situations where one input had an updated value but the other didn't.

I really wanted to get RxJS to work with this. I was only a junior developer at the time, but I spent hours and hours trying to think a way around this problem with RxJS, and came to the conclusion that it had to involve schedulers, but I didn't understand how to actually make it work.

At that point, I began to question my goal. Look at all the work I've had to go through, and it still feels awkward. Do we really want to create custom operators to make nice syntax for all of this? Why doesn't RxJS make handling derived states easier? Would it be so bad just to use selectors?

There were a lot of other Angular developers struggling with this stuff at the same time I was, and all of us concluded that selectors were the way to handle derived state in NgRx.

Selectors

Every time I see a new state management library pop up, I check to see if they use selectors, or if they require you to use distinctUntilChanged, publishReplay, refCount, combineLatest and debounceTime. Most of them do, or you have to be okay with inefficient code. RxAngular is an exception with not requiring the debounceTime, since it gives you coalesceWith, which is awesome.

I never liked the syntax of selectors, but they seemed necessary to me. So when I designed my own state management library, StateAdapt, I wanted to find a better syntax for selectors. This is what I came up with:

// NgRx:
const selectItems = createSelector(state => state.items);
const selectFilters = createSelector(state => state.filters);

const selectFilteredItems = createSelector(
  selectItems,
  selectFilters,
  (items, filters) => items.filter(filters),
);

// StateAdapt:
const adapter = buildAdapter<State>()({})({
  items: s => s.state.items,
  filters: s => s.state.filters,
})({
  filteredItems: s => s.items.filter(s.filters),
})();
Enter fullscreen mode Exit fullscreen mode

I used a proxy object s (stands for both state and selectors) that watches for the selector you're accessing and creates a more efficient memoization than createSelector.

I've been very happy with this approach. I have thought that nothing more was needed in Angular than RxJS for events and async logic, and selectors for synchronous, derived state.

But it turns out that selectors aren't perfect either.

Colocation

There are 3 types of selectors.

State selectors

These are selectors that simply select from a state object:

const selectItems = createSelector(state => state.items);
Enter fullscreen mode Exit fullscreen mode

It makes sense to export these with the reducers that manage the state they're selecting from.

Derived selectors

These are selectors that combine state from multiple reducers/stores and calculate derived state. This is derived state that doesn't belong with the top-level state, and these selectors can contain a lot of business logic.

UI selectors

These take the derived state from the first 2 selectors and change the shape of the data to be convenient for consumption in a template.

For example, let's say I had some state that described a rectangle with a position like { x: 50, y: 200 }. If that needs to be rendered as a div with CSS like style="left: 50px; top: 200px" then we could have a UI selector like this:

itemWithStyle: s => ({ left: `${s.x}px`, top: `${s.y}px` }),

<div [ngStyle]="store.itemWithStyle$ | async"></div>
Enter fullscreen mode Exit fullscreen mode

Then the component can stay lean and you can test this selector as a pure function by directly importing the state adapter and passing values to it. That's really nice. And where is a better place to put a pure function than in a selectors file where it can be tested as a pure function instead of as part of a component? And as part of a state adapter, it's reusable by default, whereas if you put the logic in the component template, you'd have to extract it in order to reuse it.

But after trying out putting UI selectors inside state adapters for a while now, I have decided that managing the same concern across 2 separate files was too awkward for the small benefit of having it in an adapter. It felt like I was polluting the derived selectors file with really boring UI concerns, and those UI concerns were more convenient colocated with the template anyway. Imagine if the template needed to implement this as an SVG. Wouldn't it be convenient to be able to edit this logic in the template instead of in a separate file? Also, in what situation would you want to reuse this UI logic? Probably when you want to reuse the component too, right?

But how do we define efficient derived state in the component? In StateAdapt it's actually not that hard, but it's not super easy either, and it definitely isn't convenient with the NgRx-style syntax.

Component inputs and the diamond problem

Another issue with both RxJS and selectors is the question of how to deal with component inputs.

For a long time, I just wanted component inputs as observables. But it turns out there's a small issue with this: If each component input gets a new value at the same time, each input observable would fire in succession, so if you needed to combine input values inside the component, a combineLatest would fire once for each input observable. Selectors can't help with this, since component inputs aren't part of the global store.

This problem actually has a name: The diamond problem.

But you know what does have really awesome syntax and handles the diamond problem perfectly? A reactive primitive that isn't RxJS: Signals.

SolidJS signal syntax is awesome

Here's a simple SolidJS component:

const CountingComponent = () => {
    const [count, setCount] = createSignal(0);
    const doubleCount = createMemo(() => count() * 2);
    return (
        <div onClick={() => setCount(count() + 1)}>
            Double count value is {doubleCount()}
        </div>
    );
};
Enter fullscreen mode Exit fullscreen mode

Here's the same thing with Angular and RxJS:

@Component({
  selector: 'app-counter',
  template: `
    <div (click)="count$.next(count$.value + 1)">
      Double count value is {{doubleCount$ | async}}
    </div>
  `,
})
export class CounterComponent {
  count$ = new BehaviorSubject(0);
  doubleCount$ = this.count$.pipe(
    map(count => count * 2),
    distinctUntilChanged(),
    publishReplay(),
    refCount(),
  );
}
Enter fullscreen mode Exit fullscreen mode

The SolidJS syntax is better for many reasons:

1. Derived or not?

In Angular you need to know you're going to have derived state in order to have a reason to use BehaviorSubject right off the bat. With SolidJS, all of your state that changes will be signals, and whether they eventually get used to derive other state does not matter. So you never need to rewrite a signal with different syntax after you first create it.

2. Recomputing

By default, SolidJS's signals will not recompute if the state they're derived from doesn't change. No need for distinctUntilChanged.

3. Shared

No matter how many signals are derived from a signal, it will not recalculate for each of them, unlike RxJS which runs a map function for each derived observable, unless you use publishReplay(), refCount().

4. Combining

When combining SolidJS signals, you don't need to define the dependency array up front like you would with NgRx selectors or combineLatest. You can just define it like c = createMemo(() => a() + b()).

And the issue with RxJS's combineLatest running once for each input is not a problem with signals. SolidJS signals wait for each dependency to finish running before they run. SolidJS signals elegantly handle the diamond problem.


Okay, now let's compare SolidJS with some examples using selectors. Here's the SolidJS code again:

const CountingComponent = () => {
    const [count, setCount] = createSignal(0);
    const doubleCount = createMemo(() => count() * 2);
    return (
        <div onClick={() => setCount(count() + 1)}>
            Double count value is {doubleCount()}
        </div>
    );
};
Enter fullscreen mode Exit fullscreen mode

Let's try Angular with StateAdapt:

@Component({
  selector: 'app-counter',
  template: `
    <div (click)="count.increment()">
      Double count value is {{doubleCount$ | async}}
    </div>
  `,
})
export class CounterComponent {
  count = adapt(['count', 0], {
    increment: state => state + 1,
    selectors: {
      double: state => state * 2,
    },
  });
}
Enter fullscreen mode Exit fullscreen mode

That's actually not bad! But it's a little more code than it has to be, as you'll see below.

Angular with NgRx would be too long, but you can imagine defining the selector in the component file:

@Component({
  selector: 'app-counter',
  template: `
    <div (click)="increment()">
      Double count value is {{doubleCount$ | async}}
    </div>
  `,
})
export class CounterComponent {
  selectDoubleCount = createSelector(
    selectCount,
    count => count * 2,
  );
  doubleCount$ = this.store.select(this.selectDoubleCount);

  constructor(private store: Store) {}
  //...
}
Enter fullscreen mode Exit fullscreen mode

Basically, selectors get the job done efficiently, but I've never seen a way to use them with as little code as signals require.

Wouldn't it be nice to have a reactive primitive in Angular that's efficient by default, with minimal syntax?

What I want

How about this:

@Component({
  selector: 'app-counter',
  template: `
    <div (click)="count.set(count.get() + 1)">
      Double count value is {{doubleCount.get()}}
    </div>
  `,
})
export class CounterComponent {
  count = signal(0);
  doubleCount = memo(() => this.count.get() * 2);
}
Enter fullscreen mode Exit fullscreen mode

SolidJS's tuple syntax isn't available, since we're assigning class properties here, but this is pretty good too.

And of course there should be a way to specify Angular inputs as signals:

@InputSignal: count!: Signal<number>;
Enter fullscreen mode Exit fullscreen mode

RxJS compatibility is still necessary

Signals are great for synchronizing derived state, but RxJS is still necessary for asynchronous reactivity. If you have any nontrivial amount of experience using RxJS it should be obvious why, but I explain a lot more in this article.

So, it would be cool if the Angular team found a way to make converting from signals to observables extremely convenient:

export class CounterComponent {
  count = signal(0);
  doubleCount = memo(() => this.count.get() * 2);
  delayedCount$ = this.count.pipe(delay(1000));
}
Enter fullscreen mode Exit fullscreen mode

The pipe would convert the signal to an observable and pass the arguments to the new observable's pipe method.

Since we're accessing an observable, hiding that pipe() logic behind a lazy import could be possible, and that would allow the RxJS code to not be loaded until it was needed.

Or Angular could copy how SolidJS does it:

const CountingComponent = () => {
    const [count, setCount] = createSignal(0);

    // signal to observable (`from` imported from 'rxjs'):
    const count$ = from(observable(count)); 

    // observable to signal (`from` imported from 'solid-js'):
    const countAgain = from(count$);
};
Enter fullscreen mode Exit fullscreen mode

Summary and conclusion

I have some strong opinions, but I also seem to change my mind a lot. But it's not like I just love moving from each JavaScript fad to the next every month. It has taken a lot of experience and pain to form my opinions, and everything I learn adds onto them.

First I thought RxJS was just a slight improvement over promises.

Then I learned about the benefits of thinking reactively, and wanted to use RxJS everywhere.

Then I learned that synchronizing state was better done with memoized selectors than with RxJS. But for asynchronous logic, RxJS was amazing, and I wanted better APIs than what Angular and NgRx provided out of the box.

Then I encountered Ryan Carniato's version of fine-grained synchronous reactivity, as well as his streams about colocation in Marko 6, and lastly people's comments on the old Angular issue describing the diamond problem for component inputs. All of this was swimming around my head until my conversation with Ryan about RxJS's problems. That's when it all fell into place and I realized there was an important role for a reactive primitive that wasn't RxJS or selectors.

So,

  • RxJS is necessary for asynchronous reactivity.
  • Selectors are necessary for reusing state management patterns with state adapters.
  • A simple reactive primitive is necessary for simple, local, reactive state synchronization.

As I work to improve StateAdapt, I will need to figure out how the new reactive primitive fits into the state management picture. I will probably start by exploring how it can be used most easily with SolidJS.

We all have different pieces of the puzzle, and I have faith that the web development community will eventually find beautiful, declarative syntax and ways of efficiently training developers with the right mindset to take advantage of reactive programming, and our industry will become increasingly productive and enjoyable to work in.


Thanks for reading!

I'd love to hear your own personal experience with anything I've shared in this article.


Cover photo by Casia Charlie: https://www.pexels.com/photo/sea-dawn-landscape-nature-2433467/

Comments 63 total

  • Maslow
    MaslowDec 7, 2022

    Very interesting read

  • Martin McWhorter
    Martin McWhorterDec 8, 2022

    Yes. A thousand times yes.

  • Mat Polutta
    Mat PoluttaDec 8, 2022

    And now I get it. I transitioned from AngularJs to Angular years back. I then transitioned from Promises to RxJS. Later I was assigned to a Dynamics CRM team where I created an Angular Library to cover all of the custom and missing components for our CRM apps. Well, whenever I went back to RxJS Observables for bug fixes or enhancements, it made my head hurt. Your examples make it very clear why. I am currently converting the Angular library to the Dynamics 365 PCF (which uses React). The Dynamics API provides for Promises, and that is what I first ported. Very timely, because my next component is invoking an LDAP API which I wrapped with RxJS Observables. It seems I'll keep it that way.

  • alexandis
    alexandisDec 8, 2022

    Oh goodness... It's still too much for my brain. I got rid of state in my code. And I do use behaviorsubject and combinelatest. It does work. I know it's not optimal, but all these things and approaches stuffed into Angular apps... It's just too much to get hands into all this. It needs to be simpler.

    • Mike Pearson
      Mike PearsonDec 8, 2022

      You will like signals

      • alexandis
        alexandisDec 30, 2022

        I already use SignalR. But I still use BehaviorSubject and CombineLatest as well... :-D

  • АнонимDec 8, 2022

    [hidden by post author]

    • Mike Pearson
      Mike PearsonDec 8, 2022

      I'm feeling skeptical about this comment

      And do you mean the general negativity, or is it something specific?

  • Brett
    BrettDec 8, 2022

    Did you check ? rx-angular.io/

    • timsar2
      timsar2Dec 8, 2022

      ‌Yes he did, He preferred rx-angular until stateAdapt being stable.

  • Oleksandr
    OleksandrDec 8, 2022

    Isnt RxJS zip do the trick for derived observables combination?
    And yes it will work if adding operators to hot observable(Subject) wouldnt make derived observable cold

    • Mike Pearson
      Mike PearsonDec 8, 2022

      I remember thinking a lot about that, but sometimes an input observable will emit when others don't.

      • Umesh Chandra Dani
        Umesh Chandra DaniDec 8, 2022

        good

      • Oleksandr
        OleksandrDec 29, 2022

        I think RxJS Observable needs kind of .pipeShare method which applies operators to hot observable and still keep it hot - it is regarding derivatives.
        But regarding combineLatest - interesting how signals do it (wait until all settled for all derivatives). curious if appying debounceTime(0) can reach same effect.

  • Michael Muscat
    Michael MuscatDec 8, 2022

    Signals make sense for functional components. I'm not convinced that signals alone will make Angular class-based components better.

    I hope that whatever solution Angular comes up with works as well in TypeScript code as it does in templates, has interop with RxJS and handles things like inputs, host bindings and queries seamlessly, and isn't an eyesore to look at.

    • Mike Pearson
      Mike PearsonDec 8, 2022

      I think it will, as long as it doesn't try to mimic something from somewhere else beyond what makes sense for Angular. If these basic requirements are met, I'm sure people will like it.

      I prefer function components, but besides syntax, it doesn't make a big difference

  • Sebastian
    SebastianDec 8, 2022

    Partially agree with @oz, about negative under tone.
    However, I think it creates nice contrast to proposed bright future.
    And your proposed API? Love it! ❤️
    Short, simple, keen, easy to use, located to scope of the component. It would play soooo nicely with Standalone components.
    You know what? You've restored my faith in Angular 😄

    • Mike Pearson
      Mike PearsonDec 8, 2022

      I'm completely clueless about the implementation details, so there might be unexpected limitations from that. And I thought for about 5 minutes before coming up with this, so there's a good chance there's something better. But I like concise things.

      As for the negativity, on certain topics I can't help it. This is my experience and I don't see a point in dressing it up. I couldn't decide what audience to write for, because there's something for every perspective to hate and love in this. So I just included all the truth I thought was relevant.

  • intermundos
    intermundosDec 8, 2022

    Another great article of why not to use angular. Over engineering at its best.

  • Umesh Chandra Dani
    Umesh Chandra DaniDec 8, 2022

    good

  • Jurugi
    JurugiDec 9, 2022

    I hate you. I'm a oldschool dev who learned from scratch since the 2000s.

    The thing is I hate you because your whole rant is based on some crybaby methodology like you don't want to learn the structured CS way that works really well, and that Angular mostly has. Angular has a nice structure that's unlike the others 'worth it' to learn and results in better results. You generally have a TS file, a HTML file, and obviously component benefit. But instead, you want some hyped up BS that 'you think' will help, but it is many step backwards. Underlying its core,all of these just runs Javascript anyway.

    What the heck are you talking about reactive primitive blahblahblah. who cares? Angular has a much better structure than React, which usually ends up a mess that tries to incoprorate HTML into 'strings' in the javascript file, that is a total joke. In Angular that's only like an 'option' and same with placing javascript easily and seamlessly anywhere, which is 'far easier' imo than React/Vue and those with the formats you said were better. Let's not get into the even more broken Vue and other JS frameworks where things you knew how to make for years, will suddenly just 'not work' and they have 'no support' for it, and it turns out to be because some novice in their new language decided that > symbol was needed somewhere, or something totally unstructured like that where they try to 'shorten things' but it ends up 'retarded'.

    Do you know why React has more jobs? Because novices copyit and use it and they get 'stuck'. Do you know why Angular has less? Because it is structured better and projects with Angular tend to be completed from start to finish. They hav less need to eventually like 'hire some expert' once your novice programmers get stuck or can't handle their own React/Vue choices and of course there's no copy pasta or indian tutorials for them to dig them out of their selfmade hole. React is not faster and there is no need for like reactive primitive whtaever this is.

    You can already do what you are describing in angular more than one way. RxJS is not even a requirement but it's just a like highly used formatting for subscribing and piping data. It's again, using underlying javascript principles, once compiled, it's not 'slower' or even 'worse' like you claimed it just because when using it, you got confused at it. In the end it has the traditional HTML, TS/Javascript, pretty easy file structures to build off. react on the other hand is a child's mess that's overhyped, and I will always spend an extra day fixing a basic thing. You among others seem to think like there's some 'reactive hype' where it's faster but you are only imagining it, it literally is not faster or even more bare bones, unless in a way like, jsx files 'are' more raw than like a compiled .ts file most times, but at that point just make it all yourself in raw javascript, so you will run into less issues and compatibility problems then?

    This just looks like a mess of an article where you say an ugly and nonused format must be better because it looks like a bit less but in reality the structure underneath is far worse performance.

    For example you say solidJS which is more like React/Vue, and that sort of format is better, but it is actually a big mess where it's essentially just the same as using a .js file, only you may run into compiler errors or mess up on it. You try to make some outlandish claim like Angular has 'a bit more lines' so thus it must be worse, but in reality, that structure it has is way better, and the 'html' component code is not required. You can also just put an HTML file which is the default and it is just cleanly alongside each .ts as a component, by default, this is so easy for any expert who thinks TS is weird to come in and learn it, as well as, suffers no speed/other issues. Putting HTML into javascript files is a mess and is a thing novices do all the time in react, then pretend like it's the new defacto standard, not realizing like, when they compile it back to raw javascript that runs on the server, it's literally juts doing the same thing, it's a step backwards to the raw javascript days where you'd write html into .js files. e.g. when you'd literaly be like placing the table rows HTML manually each line like 'lalalaa'.

    I hate that you and others like yoy are just 'cheating and lying' where you essentially just are going backwards and you learnt one script language, and you just think everything should be the way that 'you' thought it should be. Yet that 'way' is the one where experts spend more time because the frameworks are worse and get stuck on basic things again because your idea of 'better' is actually 'backwards'. Usually these things like setState and all these described things are wrappers only for Javascript's actual setLocalSession and setSessionData and yet it's a wrapper made by someone else, that ends up using that anyway.. Ridiculous to have to learn this crap just as you suggest doing and end up 5 steps backwards just because you and a few noobies wanted it.

    Ifyou are like a novice team making a car app you might have copy pasted React and have this JSX format and pretend there's something special that you praise so much (no, it's all wrappers for JS existing things). If you are like an expert and want to give the best to like a client who uses banking data and car data, more sophisticated like, you'd probably want Angular, if choosing, and I'd bet even someone who isn't as expert, would run into less problems while using that structure. Why? Because simple and efficient = better in most cases. These things you say are 'lacking' are usually just you whining it's not like the weird format seen in like Vue/React jsx files and you think like if something takes 5 lines it's better than 10 lines type of ideology, (which are, of course, no benefit really, it's backwards), the problem with this is someone 'else' made that less line of code shortened and you have no idea what it's truly doing in the backend, so when that breaks by their neglect, aformat update, or anything like that, you are screwed when it's just like your '1' line that calls a plugin doesn't work, or they just ad in some stupid symbol change like =>!<(!! (who knows), instead of just fix your '100 lines' and fix the lines yourself in like a day. Your suggestions also reminding me like back to the time of manually .js file adding html into the current page, before there were like major frameworks like these which sort of benefit and help you out, because you learnt one way, but don't understand why your suggestion is going backwards.

    • Mike Pearson
      Mike PearsonDec 9, 2022

      Lol, well I love you.

      You know, Angular was designed with a lot of of traditional CS principles. You could tell the creator really understood these patterns and encouraged Angular developers to understand and use them too. That's really what's great about it, right? So what is the creator of Angular doing now? He created a new framework called Qwik. I wonder what syntax he chose for that.

      I have been in your shoes. I was disgusted by JSX when I first saw it, and rightfully. I remember the vanilla JS days of HTML strings imperatively slapped into the DOM like it was nobody's business. I was doing that stuff in 2013. But I have a strong feeling you have never given JSX a serious try. Declarative code is what makes code maintainable, not some artificial separation of syntax style. If they're separate concerns, why do you always edit them at the same time to complete all the same tasks? I have never used the same template for multiple components, and any use case where someone has can easily be done with a shared component.

      I care about developer productivity that scales well with complexity, and reactive programming scales simply, whereas imperative programming does not. Whatever you think Angular has that removes any need for a reactive primitive, you're wrong.

      How am I arguing backwards from what I wanted from the beginning if what I've publicly argued for has changed so much over the years? I've changed my mind so much I probably have lost credibility with people who don't understand what learning feels like. And you know what, there are things I've never changed my mind on, even when there was a fad going the opposite way, because I'm capable of disagreeing with the crowd. I do it all the time.

      Here's what you should do. Spend a few weeks creating a complex React demo, and afterwards, if you still hate JSX, or whatever it is you think I like about React (this article was not about React), write an article yourself in such a logical manner that nobody could fail to be convinced by it. Don't tell your readers you hate them though. Love is the answer ✌️🕊️☮️✌️🕊️✌️✌️🕊️🕊️

      • Dominic Watson
        Dominic WatsonDec 12, 2022

        enjoyed reading the initial comment and loved your reply. Being a fullstack developer I have always rolled my eyes whenever someone suggested swapping from Angular to React or wanting to change job so they got a chance to play with it. There are bigger problems worth solving...

        It never really solved any problem we had, it was just different and more popular and that's not worth migrating for. Qwik really is a game changer and it solves a huge problem we have with server side rendering and now it's time to open your eyes and look at migrating (when it's ready and mature).

        • Mike Pearson
          Mike PearsonDec 13, 2022

          I like trying new things, but React never appealed to me until hooks in 2018/2019. Before hooks, Angular could be more declarative than React. After hooks, it flipped, and React's syntax was overall much simpler. So I liked both after that.

          I am interested in running Angular inside of Qwik. They have an integration for React that might still be buggy. So Angular might be a while still.

          • Jurugi
            JurugiDec 27, 2022

            I agree. Just to clarify though I am not stuck trying to change one to the other, I only recognize that angular is a far better toolset that actually has benefits over react. That doesn't mean that when paid to fix or upgrade someone's monstrosity react project that it was ever great to just rewrite it in better format (like raw javascript or type script), nor that they'd accept it even if you took the day or few days and fully did that. I agree in that context, it'd be extra work, so to clarify, they get what they want but still get stuck with lower performance overall by their choice.

      • Jurugi
        JurugiDec 27, 2022

        Yes, I still dislike and do not recommend react after a few instances of touching others react Frankenstein projects, where it compile a jsx file back to a js file, and things like usestate are just wrappers for session/local storage, and so on. It isn't that I couldn't rewrite it, or just use react, fyi I have completed everything I ever worked on. It's that by not swapping away and realizing limitations, they ended up with lower performance, and chose to make a quick tune up in a way, where they're likely to suffer the same issue in the future by remain ing with the bad toolsets and methodology used. In context I will never recommend writing a react project, I will only fix up or upgrade existing ones. No matter how optimal I did upgrades or fixes to some react project to get it running nicely again or add a page, If they ultimately want the lowered performance and % less efficiency by continuing to use it, I say let them learn. I'm a fan of letting those types learn the hard way, while they will even argue about how 'right' they are; or as you have done, imply like 'you probably just never used it to see the benefit', no, with me it's like the exact opposite of that.

        Most of react is backwards, placing html back into js files as strings, and compiling something that in essence is func2 calls func1 style of language anyway, as it pertains react even to raw javascript. Tutorials on what 'usestate' is a total example of this, it's like some rewrite that's really not important, yet because someone made it that way, becomes a new concept to learn somehow. Let them have more jobs because people get stuck on these Vue/react formats, lacking support, and not even understand why overall structure is better even for smaller projects. They will just remain with the 'dont change that' mentality with their less than desirable react projects, that hopefully don't scale badly (but in my experience, and with proof that there's tons of react jobs in demand, of course it does, and it did scale badly for them, they just don't understand why like I can). I'm not saying it's worth it to rewrite all react to a better format either in many cases, even if that day of rewriting will many times likely save them some headaches or some problems later. If it's simple however, and likely not to change much, then I'd say leave it alone. Again I'll generally never recommend writing a new thing in what I'll call now 'gook' script (react and weird format there) in favor of actual es6 typescript or JavaScript that runs in pure form on the browser, in some form for anything worthwhile, over some more complete toolset at least like angular where you can see 'ok that's helpful' in certain ways, or jquery which is like reacts better grandpa that still works better.

        • Guilherme Prezzi
          Guilherme PrezziJan 12, 2023

          Dude, you have to understand (and it applies to any other tech - any senior dev knows it): The problem not is (always) the React itself. It a small simple well-designed lib (and not intended to be a fw as Angular is). If you have touched a creepy React project in the past is because the programmers that made it doesn't understand well how to design it (ok that with React, because of its non-opinative way of structure, it's easier to do things wrong), and it also apply to angular projects! Do you have experienced to get a creepy angular project?? Such one that nor even the component model is respected? A such case that the data flows from nowhere to everywhere??

          If you have this such a nice experience with design patterns etc since 2000's as you described, good! try to make an App from scratch with React and apply your knowledge to it! it will be nice! The best of all worlds is to experience different things and understand what goes well and what is not!

          (also: no, usState is not a wrapper to local/session storage hahaha. It's more like a BehaviourSubject than a local storage thing. It's clear that you don't know anything about it! Please, go and use it before throwing such a 'strong' opinion on the web!)

          Best regards!

  • Omer Gronich
    Omer GronichDec 9, 2022

    SolidJS signals wait for each dependency to finish running before they run.

    Not sure this is true TBH. Just tested this in the solid playground and it seems solid memos behave the same way as combineLatest here.

    try running this solid code and check the console:

    import { render } from "solid-js/web";
    import { createMemo, createSignal } from "solid-js";
    
    function Counter() {
      const [count, setCount] = createSignal(0);
      const [count2, setCount2] = createSignal(1);
      const increment = () => {
        setCount(count() + 1);
        setCount2(count2() + 1);
      };
      const derived = createMemo(() => {
        console.count('run calculation');
        return count() + count2();
      })
    
      return (
        <button type="button" onClick={increment}>
          {count()} 
          <br / >
          {count2()}
          <br />
          {derived()}
        </button>
      );
    }
    
    render(() => <Counter />, document.getElementById("app")!);
    
    Enter fullscreen mode Exit fullscreen mode

    The memo runs twice even though the signals were changed "at the same time". It can be solved using batching or scheduling but that's true for RxJs also.

    The quotes are because values in JavaScript rarely ever change at the same time, I think multiple component inputs in angular can't ever change at the same time because angular always creates them in order synchronously.

    Great article regardless, I enjoyed it thoroughly :)

    • Mike Pearson
      Mike PearsonDec 10, 2022

      Glad you liked it!

      So what I mean by "same time" is literally same time, not just synchronous. It's called the diamond problem because you'll have a state at the top, then 2 derived states from that one, then a final derived state that combines them back again. So it's shaped like a diamond. So more like this:

      import { render } from "solid-js/web";
      import { createMemo, createSignal } from "solid-js";
      
      function Counter() {  
        const [count, setCount] = createSignal(0);
      
        const derived1 = createMemo(() => count() * 10);
        const derived2 = createMemo(() => count() * 100);
      
        const combined = createMemo(() => {
          console.count('run calculation');
          return derived1() + derived2();
        })
      
        return (
          <button type="button" onClick={() => setCount(count() + 1)}>
            {count()} 
            <br / >
            {derived1()}
            <br />
            {derived2()}
            <br />
            {combined()}
          </button>
        );
      }
      
      render(() => <Counter />, document.getElementById("app")!);
      
      Enter fullscreen mode Exit fullscreen mode

      It's actually expected if you were to set the signal values sequentially that they would run twice like in your example. In reactive programming, you never update more than one thing for each event. (Technically you shouldn't update anything, and there should just be streams that listen to events, but whatever.) You probably know, but in React it would queue the updates and rerender only once. This actually makes imperative programming easy in React. That's something I'm not interested in.

      Thanks for the comment. I didn't actually verify this before now; I just assumed based on things Ryan Carniato has said that signals behaved the optimal way. And I just checked it and it is right:

      SolidJS Diamond

      The diamond problem actually does come up quite often in real world apps. Not all the time, but often.

      • Omer Gronich
        Omer GronichDec 10, 2022

        Ohhh gotcha. That's cool. Thanks for the reply!

  • JWP
    JWPDec 10, 2022

    To me Angular's glory days ended about 7 years ago. The core team left after Angular 2, and it took them all that time to address the Ngmodel clash in Angular 14 stand alone components. With Svelte we see simplicity where even React is heavy weight.

    • Mike Pearson
      Mike PearsonDec 10, 2022

      There are a lot of good people working on Angular. I love Svelte, but a lot of web apps depend on Angular and it's a lot better for them to have an improved Angular than to migrate to something else. Angular is on par with React in every way except syntax, and signals will bridge that gap a bit and hopefully enable a performance boost to something literally impossible with React, and faster than current Svelte. It would take a big effort but I think it's possible.

  • lucaster
    lucasterDec 13, 2022

    Some things that take 4 lines of code with RxJS + Angular only take a single character with RxJS + Svelte.

    This sounds amazing! Would you provide an example?
    Thanks!

    • Mike Pearson
      Mike PearsonDec 13, 2022

      Angular

      data: Data | undefined;
      sub = this.data$.subscribe(data => this.data = data);
      
      onDestroy() {
        this.sub.unsubscribe();
      }
      
      Enter fullscreen mode Exit fullscreen mode

      Svelte

      $: data = $data$;
      
      Enter fullscreen mode Exit fullscreen mode

      That little $ prefix is telling Svelte to subscribe and unsubscribe appropriately. It's concise and declarative, but it isn't valid JavaScript; Svelte is a compiler. But it's worth it imo, because Angular's syntax is both verbose and imperative. Subscribing only breaks out of the reactive paradigm if you don't have another reactive paradigm on the other side. Svelte has synchronous reactivity built in.

      It even works in callback functions. Here's another example:

      Angular

      (submit)="saveData()"
      
      Enter fullscreen mode Exit fullscreen mode
      saveData() {
        this.data$.pipe(first()).subscribe(
          data => this.service.saveData(data);
        );
      }
      
      Enter fullscreen mode Exit fullscreen mode

      (Or you could use rxLet and pass up the unwrapped value from the template into the callback function.)

      Svelte

      on:submit={() => saveData($data$)}
      
      Enter fullscreen mode Exit fullscreen mode

      You can play with a Svelte demo I made here

      • Mike Pearson
        Mike PearsonJul 1, 2023

        Updated Example with Signals

        Angular

        data = toSignal(this.data$);
        
        Enter fullscreen mode Exit fullscreen mode

        Svelte

        $: data = $data$;
        
        Enter fullscreen mode Exit fullscreen mode

        Angular Callback

        data = toSignal(this.data$);
        
        Enter fullscreen mode Exit fullscreen mode
        (submit)="saveData(data())"
        
        Enter fullscreen mode Exit fullscreen mode

        Svelte Callback

        on:submit={() => saveData($data$)}
        
        Enter fullscreen mode Exit fullscreen mode
  • Hans Schenker
    Hans SchenkerDec 18, 2022

    I like signals for handling street traffic but not for handling state in Angular!

  • Jason Rooney
    Jason RooneyDec 20, 2022

    My frustration with Angular these days is the lack of consistency, simplicity, and compile time safety. This hits the nail on the head when it comes to RXJS.

    • There are too many ways to react to state in inputs (setters, onChanges, observable).
    • There are too many ways to implement forms (reactive, template)
    • There are too many ways to create reusable form elements (inject ngcontrol, explicitly pass in formcontrol, implement ControlValueAccessor)
    • There is no safety on inputs (can't mark as required, undefined is different than not binding to an input, inputs can't be made readonly to avoid violating 1-way data flow

    When it comes to reactive code, I believe you should be able to mix reactive code and imperative code. For derived reactive state, reactive code is fine. But reactive code gets ugly to maintain once you need to start incorporating multiple sources, state change triggers, and conditional flows.

    Consider a component which calls several http endpoints, with conditionals along the way (if service returns this then do this, otherwise do that), with triggers on formcontrol value changes, and a trigger to cancel requests on resetting the form. All along the way, you want to return data, loading state, error state. This becomes an absolute behemoth in rxjs. Is it terse? Sure. Is it easy to compose? Nope. Is it easy to refactor? Not at all.

    So many times when getting new requirements I've had to completely refactor RXJS pipes and a code change that would have been adding a simple if statement with imperative code becomes a two hour long refactoring job.

    • Mike Pearson
      Mike PearsonDec 20, 2022

      From the Angular API, I wish everything was more reactive. That would simplify things. (So, template driven forms.)

      Can you please show me an example of what you're talking about? I've had the complete opposite experience. I want to know what I might be missing. So show a current component that's completely reactive and has the stuff you mentioned, then describe a feature change that needs to be made, and we can compare how hard it is with RxJS vs imperative code.

      For now, I'm just happy that completely reactive code gives me no more race conditions or inconsistent state, improved code organization, reduced page load times, simpler state management and better function names.

      dev.to/this-is-learning/5-reasons-...

  • Ibrahim ben Salah
    Ibrahim ben SalahDec 22, 2022

    Angular is making it hard to be happy Angular developer, it is not just RxJS.
    e.g. I basically decided to never use @ContentChildren because of issues I had with it. I even tried to rewrite one of the core functionalities in Angular (the async filter) just find out that was not the issue. Also the templating issues typesafety and missing features still existing in v12 (last version I tried) was discouraging.

  • Amit Beckenstein
    Amit BeckensteinDec 28, 2022

    Very interesting read. There's indeed lots of issues with Angular and RxJS and I do hope that all the reworks of Angular prove to be good solutions. Making NgModules optional was already a great step towards better DX.

  • MT
    MTFeb 18, 2023

    The question is, why not just implement signals with RxJS, that was promoted for almost a decade?
    It's a BehaviorSubject + shareReplay + distinctUntilChanged + (perhaps) knowledge about the component lifecycle.
    Why not just create something like EventEmitter? EventEmitter extends Subject, and Signal (the name may differ) could extend BehavriorSubject with ANY additional functionality needed, specific to Angular:

    value$ = new Signal<...>(...); // Signal extends BehaviorSubject just like EventEmitter extends Subject.
    
    Enter fullscreen mode Exit fullscreen mode

    Or with decorators:

    @Signal(...) value$;
    
    Enter fullscreen mode Exit fullscreen mode

    It may know about component's ngOnDestroy etc. and be aware about Angular's inner workings.

    I've read your article, I understand that you're convinced, but to be honest I still see the main thing: Angular failed in integration with RxJS. And not they think that adding one more concept gonna change anything. No it won't.

    Why not adopt rx-angular, improve RxJS debugging with e.g. Angular DevTools, build more creational operators, improve error handling, and most importantly: improve the communication with the community?

    Let's face it: core of Angular team has left, and now the "new gen" Angular Team just uses it as their lab for experiments, following "trends" and trying to "sell" it. The future of the framework is vague. They have dropped improving the best parts of it, rewriting the engine every 2 years and changing their mind.

    By the way, they officially fake HMR: the app is fully re-bootstrapped each time: github.com/angular/angular/issues/... And it's 2023.

    So now they're gonna add "signals", then "hooks", then they would rewrite the Engine again "to support the brand new signals thing", then they'll drop RxJS "because signals are better", etc.
    While they could improve RxJS and Angular's integration with it instead.

    Now the question for you, Mike. Are you really really sure that RxJS can't cover what signals do? Maybe with another creational operator. Maybe with some improvements into RxJS itself as a lib. Are you really convinced or just gave up? :)

    • Mike Pearson
      Mike PearsonFeb 18, 2023

      I've tried so hard. But it's such a hard thing to do to convince developers of the simplicity RxJS can bring when they haven't experienced a truly complex codebase, and ultimately the Angular team is downstream from the community. Something like this was inevitable.

      But I've also been listening to Ryan Carniato's streams and I'm convinced there's just no way RxJS could be made to be as performant as signals for state synchronization. Syntax matters more to me personally. But performance is awesome too.

      As for complexity, I think most people will be surprised at how much simpler this makes everything. It's a new concept, but we get to drop a few concepts too: No more Async pipe, no more *ngIf tricks, easy access to observable values in TS without subscribing... Probably more.

      One thing I am concerned about is that they'll go too far and completely rip RxJS out even from places that work really well with RxJS. When your design decisions are driven by public opinion, you can only go so long before you create an inconsistent mess with breaking changes every year when everybody experiences pain that could have been foreseen and demands the knee-jerk reactionary opposite. If we move away from RxJS, the pain will be more and more spaghetti code.

      • MT
        MTFeb 19, 2023

        And what about contributing in RxJS to add the signal as another entity there? Make it better, make the learning curve smoother, whatever.

        import { signal, of, fromSignal } from 'rxjs';
        import { toSignal } from 'rxjs/operators';
        
        const observable: Observable = of([]);
        const signal: Signal = signal(1);
        
        const signal2 = observable.pipe(map(...), flatMap(...), toSignal());
        const observable2 = fromSignal(signal2);
        
        const signal3 = () => signal2() * 2;
        
        Enter fullscreen mode Exit fullscreen mode

        They already have e.g. Subjects, why not add Signals too...

    • Timur Mishagin
      Timur MishaginMar 15, 2023

      Yes, can agree with you. For me it's more and more clear that sooner or later it will be easier to migrate a project to Svelte rather than trying to get in touch with Angular's "cutting edge" point of view.

      Why do I need to bother in choosing between RxJs or signals if I can just use Svelte's stores? It's just stupidly easier, isn't it?

      • Mike Pearson
        Mike PearsonMar 15, 2023

        Ugh, Svelte stores are the worst. They're just less-capable versions of BehaviorSubject.

        • Timur Mishagin
          Timur MishaginMar 16, 2023

          Maybe, but I don't have any example which might be a proof that BehaviorSubject is superior...

          By the way, signals are not bad, but the way it's implemented in Angular it's bsht as for me. If Angular wants to catch up the others why should I go with it if others do it better (less verbose, more elegant and so on)?

          I just looked at how ngrx is adopting signals and I was about to bloat. I wanted to say there the same crytics as here, but I didn't. I don't want upset the developers since they're at least trying. As it was mentioned it's not NgRx or RxJs, but Angular...

          • Mike Pearson
            Mike PearsonMar 16, 2023

            Anything with .pipe() is an example where BehaviorSubject is superior.

            If you watch the video with Ryan Carniato and understand how the Angular team made signals, I actually think it's the best designed they could have possibly come up with, given the constraint that they are to be used in classes. The interop with RxJS could be better, but the signals themselves are very, very good.

  • Giuseppe
    GiuseppeFeb 19, 2023

    I understand Signal’s advantages but If it will be a substitute of rxjs means that all current applications that use rxjs will probably need a deep refactoring. It’s like what we had when we moved from Angularjs to Angular 2!!! If my thoughts will became reality i will not choose anymore google framework for develop applications!

    • Mike Pearson
      Mike PearsonFeb 19, 2023

      I think that's a bit of an exaggeration :)

      I've been helping teams upgrade from AngularJS to Angular for the past 2 years and this is like 10% the size of that change. It's incrementally adoptable and will drastically simplify components. It will make it easier to use RxJS with Angular.

      And believe me, if Angular made it even more difficult to use RxJS in Angular, I would start making tools to help teams migrate away from Angular. Declarative code is more important than any single framework.

  • 井上 オースティン
    井上 オースティンFeb 23, 2023

    I really enjoyed your article, thank you!

    I think Angular’s decisions to lower the initial learning curve is going to lead to more interest in the long term and Signals could be a big part in helping that.

    The biggest reason why I use angular is that it can solve code organization problems that other libraries frankly are ill equipped to solve. The injection systems, Services, Angulars Router, Module system, these are all very well done and can be used to organize big code bases.

    I am worried like others that angular may drift from RxJS as RxJS is very very much a high end master level library.

    Interoperability between signals and Observables as seen in SolidJs could give us the best of both worlds, removing the clutter of the Async pipe.

    The angular team is saying that they are prioritizing interoperability so this could be a way to fix the problems of RxJS integration.

    Id love to see as @InputSignal decorator which could also be converters to an Observable then piped.

  • Jason Aunkst
    Jason AunkstFeb 24, 2023

    RxJS is still more portable than an angular signal primitive.

    Also you’re not going to deal with async situations like switch map with a signal.

    • Mike Pearson
      Mike PearsonFeb 24, 2023

      Yes. I just think of signals as a good way of managing component-level reactivity. Like AsyncPipe++

  • timsar2
    timsar2Mar 8, 2023

    I would like to start a new project and use state-adapt, but this two week ppl are talking about signals and I think it would be good to use signal now instead of refactoring my app 6 month later.
    It would be good if you can add a sample implemented with signals to state-adapt, like ngrx/signal-store:
    github.com/ngrx/platform/discussio...

    • Mike Pearson
      Mike PearsonMar 8, 2023

      Here's what will not change with signals:

      • Sources
      • Selectors & state adapters

      Here's what will change:

      • Not using the async pipe
      • Might add a convenience function, but seems a bit unlikely for now

      StateAdapt takes advantage of RxJS behavior of doing nothing until something needs it. fromObservable subscribes immediately. This means the role for signals is pretty small in StateAdapt.

      Signals are good for synchronously derived, non-reusable state. So, state that is forever local to a component. That's a very small part of overall state management.

      All these libraries diving headfirst into signals are going down a path that restricts how reactive and flexible state management can be. It's not a good idea. Especially this early on... The best way to reduce the amount of refactoring you'll need to do is to start very conservatively with signals and learn all about them before you tie everything to them. Edit: Remember, this is just an RFC and the PR for fromObservable hasn't even merged yet. There is a high chance of the signal API itself changing.

      • timsar2
        timsar2Mar 9, 2023

        I follow your content closely and thank you for sharing your experiences.
        I was deciding to pick rx-angular and state-adapt to make zone-less my ionic mobile application (a mini social-media :D) until this days when signals come to angular preview.
        So I'll start the app within a month later to learn and see more about signals from RFC.

  • Lars Rye Jeppesen
    Lars Rye JeppesenFeb 5, 2024

    Happy now? :)

Add comment