Why use OnPush in Angular? Not for performance...

แชร์
ฝัง
  • เผยแพร่เมื่อ 12 ก.ย. 2024

ความคิดเห็น • 54

  • @JoshuaMorony
    @JoshuaMorony  ปีที่แล้ว

    Join my mailing list for more exclusive content and access to the archive of my private tips of the week: mobirony.ck.page/4a331b9076

  • @phugia963
    @phugia963 ปีที่แล้ว +35

    first off I think it's great to have deep knowledge about Angular stuffs (change detection, rxjs) & messing with them. But after refactoring, you ended up with 2 nested pipes and a HOO (Higher Order Observable) inside another HOO, which definitely harder to debug & understand. Async pipe might be great but if it make your code harder to read & trace, just go with the normal way, subscribe & assign value to a variable, bind that value to template & let Angular take its course.

  • @maximlyakhov967
    @maximlyakhov967 ปีที่แล้ว +14

    I would create BehaviorSubject and push new values within the Input setter and a subscription to subject with delay to project the data to template. This would be easier to test and the data is split from reactive mapping without introducing flattening operators.

  • @walboey
    @walboey 2 ปีที่แล้ว +5

    I'm back into working w/ angular and searched a topic and now your all videos are being recommended to me. I am not disappointed; your videos are excellent!

  • @davesuico9950
    @davesuico9950 2 ปีที่แล้ว +6

    Thank you for your efforts! I've finally found a better angular channel to learn from!

  • @Blafasel3
    @Blafasel3 ปีที่แล้ว +8

    Nice video! I switched over to using onPush for every component for the reasons you mentioned. Another reason I see which is not explicitely mentioned: Once you understand when the changeDetection is triggered when set onPush, it becomes very clear and concise (and easy to test) changes in the component because there is only a very limited number of events if your component is as small as it should be. There is also no way for someone else to mess changeDetection up - I've seen horrible inplace mutation of arrays and objects inside that array which only worked because of the default Angular ChangeDetection setting. I honestly believe there should only be OnPush or it should be the default at least. Even for small apps. Performance gain is nice 2 have and makes sense, but as you said, it just makes you write much clearer code which is way easier to understand if you just take the time to watch your explanation ;)

  • @Jul05
    @Jul05 ปีที่แล้ว +3

    Thank you so much! All of your videos are amazing! You are the best source for advanced Angular topics by far.

  • @JoboyJordan
    @JoboyJordan ปีที่แล้ว +1

    Hi Joshua, thanks for this great video 👍 It gave me clear understanding on the benefits of creating components reactively (also functional via pipe()). I'm the one who asked ealier regarding the benefits of why use RxJS over standard way. I think this video answered that. THANKS!

  • @ravindradevrani
    @ravindradevrani ปีที่แล้ว

    What a clean explanation. Great content as always.

  • @omergronich778
    @omergronich778 2 ปีที่แล้ว +11

    Correction- the async pipe does not trigger change detection, it calls markForCheck that tells angular to check the component in the next change detection cycle

    • @ytamb01
      @ytamb01 2 ปีที่แล้ว +1

      That sounds like a subtle, but important, point. What's the difference? When would the next change detection cycle be?

    • @omergronich778
      @omergronich778 2 ปีที่แล้ว +11

      ​ @Andy Brewer
      Angular uses zone.js to trigger change detection.
      So the following things can trigger change detection in angular:
      1. all things zone.js patches (Web apis, browser events, ajax requests etc...)
      2. manually calling detectChanges() which tells Angular to run change detection on the component and it's children
      3. calling ApplicationRef.tick() which tells Angular to run change detection for the whole application.
      By default angular will check every single component in the component tree for changes unless that component's change detection strategy is set to OnPush, in that case angular decides whether to skip that component or not. The way it determines whether to skip it is by checking the following things:
      1. If an Input reference has changed
      2. An event originated from the component or one of its children.
      3. The component was marked for check (like what the async pipe does)

    • @omergronich778
      @omergronich778 2 ปีที่แล้ว +1

      ​ @Andy Brewer
      hope that clears it up

    • @JoshuaMorony
      @JoshuaMorony  2 ปีที่แล้ว +12

      I am aware of this so hopefully the video isn't misleading, I mentioned that the async pipe also uses the CDR to trigger change detection - which it does by using markForCheck() and then a tick() is triggered, which is going to cause the component to be updated just like detectChanges() would do if we did that manually ourselves. Maybe the video could have been clearer here, but it's also a deeper point that I didn't really want to get bogged down on. Thanks for the comment!

    • @konstantinkim4148
      @konstantinkim4148 ปีที่แล้ว

      then why the example works with all the photoes? With markForCheck changeDetection only works on the next cycle, but here we got all the photoes displayed instead of skipping the last one

  • @tristanmorris5646
    @tristanmorris5646 4 หลายเดือนก่อน

    Some comments are taking this video as evidence that rxjs is bad (at least for this situation). But there's always multiple ways to do something, and maybe people might find something like this more intuitive:
    this.currentPhoto$ = zip(interval(500), from(value.reverse())).pipe(
    map(([intervalIndex, photo]) => photo)
    }
    Learning zip, interval, and from can be tricky, but the hardest one here is zip... and playing with the rxjs marbles diagram for it gives an intuitive understanding super quickly.

  • @julienwickramatunga7338
    @julienwickramatunga7338 2 ปีที่แล้ว

    Really nice example, thank you very much!

  • @jordisarrato331
    @jordisarrato331 2 ปีที่แล้ว

    I use change detection in my website and this is very interesting!

  • @JohanCoppieters
    @JohanCoppieters 2 ปีที่แล้ว +7

    I must say the onPush: I’m totally pro. Makes you think about your code.
    As a lecturer, developer and dev mgr, I often see functional code which is very readable at writing time and while explaining. However for other developers reading your code and even for yourself 2 years later, it’s hard see what it does exactly.
    The number of lines doesn’t matter, readability to other people is much more important.

    • @frankseverijnen859
      @frankseverijnen859 2 ปีที่แล้ว +4

      Second this. Readable code is in most cases way more important than the most technically beautiful code.

  • @RoiTrigerman
    @RoiTrigerman 2 ปีที่แล้ว +1

    Thanks for the great videos :) Regarding the photos example, I see many people saying that you shouldn't pass an observable to an input. Do you disagree?

    • @JoshuaMorony
      @JoshuaMorony  2 ปีที่แล้ว +2

      I generally agree, most of the time I will use the async pipe to subscribe to the stream and pass synchronous values to the component as an input. Important not to be too dogmatic about these things though, sometimes breaking the "rules" can be beneficial or useful. One argument for passing in an observable as an input is that the input reference won't change so there is going to be less change detection triggered with OnPush - so potential significant performance gains there under the right circumstances. Maybe sometimes it just makes the code easier/cleaner and that's fine too.

  • @xxRAP13Rxx
    @xxRAP13Rxx 2 หลายเดือนก่อน

    Thanks for the video! At 6:50, onPush change detection strategy won't enable change detection because `currentPhoto` isn't marked with @Input() ?

  • @pippaloves
    @pippaloves 10 หลายเดือนก่อน

    Thank your for this video

  • @bronzekoala9141
    @bronzekoala9141 ปีที่แล้ว

    Nice, however I shiver at the thought of unittesting stuff like this.

  • @TheSaceone
    @TheSaceone 2 ปีที่แล้ว

    thank you for the video! it's gonna be useful for a particular feature I'm working on in an app of mine! Btw why did you reverse your photo array?

    • @JoshuaMorony
      @JoshuaMorony  2 ปีที่แล้ว

      Just because I wanted the photos to display in reverse order (last should be shown first) - nothing special going on there!

  • @Almighty_Flat_Earth
    @Almighty_Flat_Earth 2 ปีที่แล้ว +1

    Would have been better if you had provided stackblitz example.

  • @dale_nguyen
    @dale_nguyen 2 ปีที่แล้ว

    Thanks for the video 👍

  • @samucancld
    @samucancld ปีที่แล้ว

    Great video 👍

  • @WanderingCrow
    @WanderingCrow 2 ปีที่แล้ว

    Thanks a lot for this video, this is actually something I've started to do recently, so I'm glad to see the long-term benefits it can bring. Also, I must confess being a little disappointed by your newsletter, that enforce the use of a .subscribe(), instead of your beloved async pipe 🤔😏

  • @LeungWong
    @LeungWong 2 ปีที่แล้ว

    What’s the approach to detect change in dynamic created components? You would need to use ChangeDetectorRef right?

  • @bobar92
    @bobar92 2 ปีที่แล้ว

    Thanks for the video! Is there a way to set OnPush globally, instead for each component, or would you advise against doing it for every component?

    • @GLawSomnia
      @GLawSomnia 2 ปีที่แล้ว +2

      You can set it in angular.json, but it will only affect the components that you will create in the future (with the CLI)

    • @JoshuaMorony
      @JoshuaMorony  2 ปีที่แล้ว +2

      What GLaw said, also you can supply flags when generating components if you want, and I would not advise against it - I think you should do it for every component :) having some OnPush and some not would probably just make things confusing.

    • @bobar92
      @bobar92 2 ปีที่แล้ว +1

      @@GLawSomnia Thank you for the answer!

    • @bobar92
      @bobar92 2 ปีที่แล้ว +1

      @@JoshuaMorony Thanks for the answer, I think I'll do that from now on 😁

  • @stanisawgolinski3244
    @stanisawgolinski3244 2 ปีที่แล้ว +1

    Isn't pushing Observables through Input an antipattern?

    • @JoshuaMorony
      @JoshuaMorony  2 ปีที่แล้ว

      I responded to a similar question in another comment: "I generally agree, most of the time I will use the async pipe to subscribe to the stream and pass synchronous values to the component as an input. Important not to be too dogmatic about these things though, sometimes breaking the "rules" can be beneficial or useful. One argument for passing in an observable as an input is that the input reference won't change so there is going to be less change detection triggered with OnPush - so potential significant performance gains there under the right circumstances. Maybe sometimes it just makes the code easier/cleaner and that's fine too."

  • @noss403
    @noss403 2 ปีที่แล้ว

    And how to stop/interrupt this slideshow?

  • @IamPali2024
    @IamPali2024 4 หลายเดือนก่อน

    This example shows why exactly you shouldn’t use onPush. And if there are any performance gains, it should be Angular who come up with performance updates for their product not developers

  • @CeezGeez
    @CeezGeez ปีที่แล้ว

    ty

  • @rajatnegi3896
    @rajatnegi3896 2 ปีที่แล้ว +2

    I like your accent man

  • @aqliyusoff8355
    @aqliyusoff8355 2 ปีที่แล้ว

    get a helping answer thanks.....

  • @The14Some1
    @The14Some1 10 หลายเดือนก่อน

    11:25 ain't this violate the "reactive" coding rule? You must have subscribed somewhere to get the list of photos as an array.

  • @lucasgiunta8874
    @lucasgiunta8874 2 ปีที่แล้ว

    But it is not a good practice to give a stream to a component.

    • @JSCHM
      @JSCHM ปีที่แล้ว +1

      In the last version of the code no observables are passed between components. Instead, the setter converts the value to an observable (and the currentPhoto$ observable is "converted" back to a normal value via the `async`-pipe).

  • @ItsBlew
    @ItsBlew 2 ปีที่แล้ว

    Sae

  • @tudorcranfield2183
    @tudorcranfield2183 2 ปีที่แล้ว

    😂 Pᵣₒmₒˢᵐ

  • @komodoutd
    @komodoutd 2 ปีที่แล้ว +1

    Couldn't you have totally skipped concatMap here and just go with this:
    from(value.reverse()).pipe(delay(500)) ?

    • @JoshuaMorony
      @JoshuaMorony  2 ปีที่แล้ว +4

      The delay operator will add a delay before the stream starts emitting, but it won't add a delay for *each* emission. That's why the concatMap is required here, because I want to wait 500ms between each emission, so I have to create an individual stream for each individual photo so that the delay will work how I want.

    • @komodoutd
      @komodoutd 2 ปีที่แล้ว

      @@JoshuaMorony Yes, now it makes sense. thanks a lot for the detailed explanation!