Fantastic closures and how to find them in React

Sdílet
Vložit
  • čas přidán 13. 08. 2023
  • 👉 Advanced React Book: www.advanced-react.com
    👉 Fantastic closures and how to find them in React: www.developerway.com/posts/fa...
    💬 Twitter: / adevnadia
    💬 Linkedin: / adevnadia
    👩🏼‍💻 Initial "mystery" code example: codesandbox.io/s/example1-925...
    👩🏼‍💻 Cached closure without React code example: codesandbox.io/s/example2-xx4xq3
    👩🏼‍💻 "Mystery" app fixed with the solution code example: codesandbox.io/s/example5-h3j...
    Closures in JavaScript must be one of the most terrifying features of the language. Even the omniscient ChatGPT will tell you that. It’s also probably one of the most hidden language concepts. We use it every time we write any React code, most of the time without even realizing it. But there is no getting away from them in the end: if we want to write complex and performant React apps, we have to know closures.
    So let’s dive into yet another code mystery, and in the process learn:
    * What closures are, how they appear, and why we need them.
    * What a stale closure is, and why they occur.
    * What the common scenarios in React are that cause stale closures, and how to fight them.
    #react #reactjs #webdevelopment #programming #frontend #frontenddeveloper #js #javascript

Komentáře • 77

  • @FilipCodes
    @FilipCodes Před 3 měsíci +4

    Closure - snapshot with all outside data frozen in time and stored in memory. Perfectly explained 👌

  • @ghostrAider98
    @ghostrAider98 Před 4 dny

    Thank you. Probablythe best way of teaching an optimization technique and it's core underlying principle and closures I've seen. Rare quality content

  • @aleksandrmatyka3118
    @aleksandrmatyka3118 Před 11 měsíci +8

    You have a talent for teaching, thanks for another great article

  • @codewithelvin
    @codewithelvin Před 11 měsíci

    Love the way you explain. Thanks much 🙏 Keep going with much such deep dives.

  • @GKiant
    @GKiant Před 11 měsíci +1

    one of the best closure explanations i've seen so far. Thank you so much!

  • @Ziko675
    @Ziko675 Před 11 měsíci

    I was waiting for your video ever since I watched your reconciliation video. So beautifully explained

  • @JoeBuza
    @JoeBuza Před 11 měsíci +8

    I love the way you explain advanced concepts. It’s so beautifully laid out and easy to consume. What do you use for your presentations? I like the arrows you draw on them.

  • @devquen7688
    @devquen7688 Před 11 měsíci +1

    Love the way you explain deeply about ReactJS. Thanks very much🚀 Keep it up.

  • @JamesBoyle-xj3yj
    @JamesBoyle-xj3yj Před měsícem

    I read your book twice, now im happy to find your making videos too... The best react content out there BY FAR.. thank you

  • @belkocik
    @belkocik Před 6 měsíci

    I've never heard about that! This kind of videos you make are just gold!

  • @umutpalabyk9834
    @umutpalabyk9834 Před 11 měsíci

    Excellent explanation. Tnx Nadia.

  • @sushantrajbanshi4508
    @sushantrajbanshi4508 Před 10 měsíci

    Your channel is like a GOLD MINE for us React Developers. You don't only just teach us the React ..but make us love it's internals and functionalities. Love it 💛

  • @aissanadjemeddine1330
    @aissanadjemeddine1330 Před 4 měsíci

    Amazing explanation , Thanks so much

  • @sarazamani4914
    @sarazamani4914 Před 9 měsíci

    I have watched all of your videos and I have learned valuable lessons from each one. I am truly grateful for the knowledge you have shared. Thank you.

  • @zdargahi
    @zdargahi Před 10 měsíci

    Thanks Nadia, what a high quality video, love your articles too

  • @xXLeGrandStanXx
    @xXLeGrandStanXx Před 10 měsíci

    Just watched, and liked all your videos.
    Thank you.

  • @rainysky84
    @rainysky84 Před 11 měsíci

    Nice trick with React.Refs in the end of the video,
    Thanks!

  • @bigproduction3999
    @bigproduction3999 Před 11 měsíci

    thank you! nice video

  • @amantulsyan1082
    @amantulsyan1082 Před 11 měsíci

    This video was very useful

  • @hamdaniash-siddiq5021
    @hamdaniash-siddiq5021 Před 4 měsíci

    When i see your vide, i know it’s going tobe a very informative one. I love the way you explain things to the point and crystal clear. Thanks

  • @alieman9154
    @alieman9154 Před 5 měsíci

    What's the hardest part ? Understanding deeply the topic ?
    Or creating the visual slides, narrating it as if it's one shot, & making it stick to end user ?
    Indeed what a profound work... It sticked to me definitely, reading your Advanced React book & then discovering these.

    • @developerwaypatterns
      @developerwaypatterns  Před 5 měsíci +1

      Finding a way to explain a complicated topic that it seems trivial afterwards is the hardest part :)

  • @_ghostman
    @_ghostman Před 6 měsíci +1

    You deserve so many more subscribers. Honestly some of the best React content out there.

  • @UIDEVELOPER
    @UIDEVELOPER Před 11 měsíci

    Great work Nadia!

  • @Pawansoni432
    @Pawansoni432 Před 6 měsíci

    Thank you❤😊

  • @tanercoder1915
    @tanercoder1915 Před 11 měsíci

    instant like to your videos. like even without watching.

  • @Alastairtheduke1
    @Alastairtheduke1 Před 11 měsíci

    Superb explanation of one of the most misunderstood topics. Thank you

  • @cagrakar792
    @cagrakar792 Před 7 měsíci

    Perfect example !

  • @Yoband706
    @Yoband706 Před 11 měsíci

    I was so not sold for the first 18 minutes of the video. I wrote the problem off as "wrongly optimised React (refer to Nadia's other videos to do it correctly :D)". What a twist at the end calling `ref` in the `useCallback` hook🤯! Great content as always.

  • @omprakashdeshmukh9850
    @omprakashdeshmukh9850 Před měsícem

    Hi Developer, you are creating the best videos, please create videos for JavaScript as well.

  • @anwarbaig8037
    @anwarbaig8037 Před 13 dny

    Ma'am,your video are best.

  • @uzochukwuamarabenneth2583
    @uzochukwuamarabenneth2583 Před 11 měsíci

    Great content. I just use React hook forms for anything form related and that would prevent rerendering on keystroke, i also use something like ref.current.value sometines.

  • @user-ev3sy3ek4m
    @user-ev3sy3ek4m Před 6 měsíci

    just wow!!

  • @engincandinc9328
    @engincandinc9328 Před 11 měsíci

    Thanks a lot for these deep dive explanation. Amazing content as always! I'm curious about how we can use an alternative solution:
    How would we fix this problem by "Playing with composition and getting rid of state completely"?

    • @developerwaypatterns
      @developerwaypatterns  Před 11 měsíci +1

      A full answer would be another big artile and video 😅
      For getting rid of state, we could just access the value in the input directly through ref. If we don't need it for anything other than sending to backend, it could be an option.
      For composition, would have to refactor the "heavy" component to extract the button away from it, and then go with any of this approaches: www.developerway.com/posts/react-re-renders-guide#part3
      Or extracting the value into context and accessing it in the button directly (maybe)

    • @engincandinc9328
      @engincandinc9328 Před 11 měsíci

      @@developerwaypatterns Makes sense, thank you for your reply!

  • @lovikuanyshev
    @lovikuanyshev Před 7 měsíci

    what a really interesting solution, but how often should you use this case instead of decomposition or another preventing re-renders steps?

  • @ganeshkhirwadkar4127
    @ganeshkhirwadkar4127 Před 11 měsíci

    Just wowwwww

  • @carmelk82
    @carmelk82 Před 5 měsíci

    Awesome explanation! is there a small chance that useEffect wont trigger before user clicks, and click function will not be updated yet? In that case is it better to use useLayoutEffect instead of useEffect to be 100% consistent? If switched to repaint blocking useLayoutEffect, will it always be better to use it instead of the initial way, heavy component without memoization?

    • @developerwaypatterns
      @developerwaypatterns  Před 5 měsíci

      I doubt it's possible in real life, tbh.
      And useLayoutEffect might be very harmful to performance - it will force the entire component and everything that use it to be "synchronous"

  • @ehm-wg8pd
    @ehm-wg8pd Před 10 měsíci

    i learned this in hard way

  • @Alastairtheduke1
    @Alastairtheduke1 Před 11 měsíci

    18:43 I would have never come up with this

  • @ru2979
    @ru2979 Před 11 měsíci

    wow so cute 🥺

  • @SachinYadav-yx1rc
    @SachinYadav-yx1rc Před 6 měsíci

    Great Video.
    I have a question if the HeavyComponent only had the onClick as props and not the title (which is a primitive data type) then how would have you used React.memo because we cannot compare the onClick since it would be a non-primitive. Am I missing out on something here ?

    • @developerwaypatterns
      @developerwaypatterns  Před 6 měsíci

      In this example, if you remove the title, you can just return the boolean without doing any comparisons:
      const HeavyComponentMemo = React.memo(HeavyComponent, () => {
      return true;
      });

    • @SachinYadav-yx1rc
      @SachinYadav-yx1rc Před 6 měsíci

      @@developerwaypatterns understood thank you

  • @RealToptuK
    @RealToptuK Před 11 měsíci

    Thank you for your article.
    But i don't completely understand this: "We're supposed to modify Refs inside useEffect, not directly in render, so let's do that."
    Why not do it directly in the render?

    • @developerwaypatterns
      @developerwaypatterns  Před 11 měsíci

      React team recommends agains it, it might not be compatible with future React versions:
      react.dev/reference/react/useRef
      See the "pitfall" section there

  • @isaacjon
    @isaacjon Před 7 měsíci

    you said ref by itself an obj preserved between re-renders by React. if its preserved why cant we pass it directly to heavyComponent because it should not make rerenderrs if its preserved

  • @ehm-wg8pd
    @ehm-wg8pd Před 6 měsíci

    The solution to avoid stale closure value and reference is to pass them as arguments

  • @kirylparfiankou1115
    @kirylparfiankou1115 Před 10 měsíci

    Hello! Why do we need to wrap `ref.current = () => { console.log(state); }` into useEffect ? Why not just write an assignment ref.current = ...? in `const Component = () ={ ... }` ? So it will also be called on every render. Thank you :)

    • @kirylparfiankou1115
      @kirylparfiankou1115 Před 10 měsíci +1

      Oops, found the answer on the site. Not relevant:)

    • @developerwaypatterns
      @developerwaypatterns  Před 10 měsíci +1

      Maybe post the answer here, so that everyone can benefit if they have the same question 😉

  • @isaacjon
    @isaacjon Před 7 měsíci

    i am wondering.
    You said that we can't pass ref directly into HeavyComponent, because it changes with every state change when user type, and causes rerender of HeavyComponent, which means if we pass ref into HeavyComponent react doesn't preserve it. If it would preserve useRef, HeavyComponent would not rerender. But after a few seconds you're saying that useCallback does not need ref as a dep arr because react preserves ref. if react preserved it you could pass it to HeavyComponent and it would not make this component rerender because its preserved. Help I am confused.

    • @developerwaypatterns
      @developerwaypatterns  Před 7 měsíci +1

      In the code example for the video, we're updating state on every keystroke, and assigning a callback function to ref.current on every state update.
      Ref doesn't cause any re-renders, but the state update does. And since we're updating ref on every state update, if we pass that ref as a prop to the HeavyComponent, this prop will change with every state update as well.
      As a result, memoization for it is broken, and it will re-render as if it was not wrapped in React.memo

    • @isaacjon
      @isaacjon Před 7 měsíci

      @@developerwaypatterns okay i got it. But how come useCallback can be aware of new value of ref.current, if it's already closed over in the first render of parent component with ref.current being undefined? I think when useCallback closed over useRef, it was undefined and that value is never updated because we didn't pass it in the dep array

    • @developerwaypatterns
      @developerwaypatterns  Před 7 měsíci

      It closed over the ref itself, which is an object :) And the reference to that object doesn't change - useRef takes care of it. When we mutate an object, we're not creating a new object, we're mutating an existing object - the one that we have reference to via `ref` itself.

    • @isaacjon
      @isaacjon Před 7 měsíci

      @@developerwaypatterns thank you 👍

  • @paulstelian97
    @paulstelian97 Před měsícem

    4:20: Well the problem _just_ mentioned clicked for me and holy cow it’s an annoying and unintuitive issue! Before watching further, my guess is:
    * Since count is captured at the time of the closure, it’s frozen in time to whatever it is when the callback is registered
    * Memoization prevents the component from being re-rendered and the closure being replaced with an up-to-date closure with the most recent state
    * The worst part is I don’t see an obvious solution (does the rest of the video offer one? I expect so, but I’ll watch patiently) as calling useState in an event handler is not gonna work. useRef()? Shouldn’t be needed….
    I’ll keep watching.
    Edit: oh fuck I saw the name of the last chapter. It is, in fact, refs that are used for it. 💀
    Edit 2: Well that’s a more clever way to use the closures than I thought.

  • @PaulSebastianM
    @PaulSebastianM Před 8 měsíci +3

    There is no such thing as a stale closure. It's an term invented for things devs don't understand how they work. In this case closures, and the JS language.

    • @ehm-wg8pd
      @ehm-wg8pd Před 6 měsíci +2

      that make sense, it sounds like the stale closure is unintended behaviour , in fact closure is always stale

  • @satejbidvai
    @satejbidvai Před 8 měsíci

    Isn't using ref here overomplicating things? Like it solves our problem but the solution seems hacky and not the best way to go with.
    I'm in no way criticising your content, it is legit quite good. Just wanted to have this doubt cleared.

    • @developerwaypatterns
      @developerwaypatterns  Před 8 měsíci

      Well, there are always multiple ways to solve the same problem. What would you prefer instead of this one?

    • @satejbidvai
      @satejbidvai Před 8 měsíci

      @@developerwaypatterns I don't exactly know of a way😅
      I just wanted to confirm if this method is used normally in codebases. Maybe it looks hacky to me because I have never seen or implemented it before.

    • @developerwaypatterns
      @developerwaypatterns  Před 8 měsíci

      @@satejbidvai haha, got it 😅It's complicated and requires a good understanding of closures and React, so that's probably why you haven't see it yet - it's not that popular.
      But you probably used it without realizing it, if you use popular hooks libraries. Some of them use it to implement memoization without dependencies.

    • @satejbidvai
      @satejbidvai Před 8 měsíci +1

      @@developerwaypatterns that makes sense. This was really helpful. Much thanks ✨

  • @valerijlobanov4199
    @valerijlobanov4199 Před 5 měsíci

    You are brilliant . Your only lack is you are from Russia.

  • @meliko6
    @meliko6 Před 7 měsíci

    mind blowing solution

  • @markokraljevic1590
    @markokraljevic1590 Před 11 měsíci

    why not compare props.title === prevProps.title && props.onClick !== prevProps.onClick in React.memo() too?

    • @Myszko3321
      @Myszko3321 Před 11 měsíci

      Correct me if I am wrong, but I'm pretty sure that this would do nothing since you would have to wrap the onClick function inside a useCallback, which would have to be dependant on the state. This would resolve in creating a new function, and a new reference, for each render and this condition would be always equal to false.

    • @markokraljevic1590
      @markokraljevic1590 Před 11 měsíci

      ​@@Myszko3321dont wrap it in useCallback at all, just skip rerender if it changes

    • @developerwaypatterns
      @developerwaypatterns  Před 11 měsíci +1

      You'll have exactly the same problem as described in the video then, when state inside is not updated