Fantastic closures and how to find them in React
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
Closure - snapshot with all outside data frozen in time and stored in memory. Perfectly explained 👌
Thank you. Probablythe best way of teaching an optimization technique and it's core underlying principle and closures I've seen. Rare quality content
You have a talent for teaching, thanks for another great article
Love the way you explain. Thanks much 🙏 Keep going with much such deep dives.
one of the best closure explanations i've seen so far. Thank you so much!
I was waiting for your video ever since I watched your reconciliation video. So beautifully explained
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.
Thank you! I use Keynote on Mac
Love the way you explain deeply about ReactJS. Thanks very much🚀 Keep it up.
I read your book twice, now im happy to find your making videos too... The best react content out there BY FAR.. thank you
I've never heard about that! This kind of videos you make are just gold!
Excellent explanation. Tnx Nadia.
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 💛
Amazing explanation , Thanks so much
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.
Thanks Nadia, what a high quality video, love your articles too
Just watched, and liked all your videos.
Thank you.
Nice trick with React.Refs in the end of the video,
Thanks!
thank you! nice video
This video was very useful
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
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.
Finding a way to explain a complicated topic that it seems trivial afterwards is the hardest part :)
You deserve so many more subscribers. Honestly some of the best React content out there.
Thank you! Let's make it happen 😀
Great work Nadia!
Thank you❤😊
instant like to your videos. like even without watching.
Superb explanation of one of the most misunderstood topics. Thank you
Perfect example !
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.
:D
Hi Developer, you are creating the best videos, please create videos for JavaScript as well.
Ma'am,your video are best.
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.
just wow!!
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"?
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)
@@developerwaypatterns Makes sense, thank you for your reply!
what a really interesting solution, but how often should you use this case instead of decomposition or another preventing re-renders steps?
Probably not that often, but it's good to have it in your arsenal :)
Just wowwwww
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?
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"
i learned this in hard way
18:43 I would have never come up with this
wow so cute 🥺
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 ?
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;
});
@@developerwaypatterns understood thank you
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?
React team recommends agains it, it might not be compatible with future React versions:
react.dev/reference/react/useRef
See the "pitfall" section there
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
The solution to avoid stale closure value and reference is to pass them as arguments
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 :)
Oops, found the answer on the site. Not relevant:)
Maybe post the answer here, so that everyone can benefit if they have the same question 😉
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.
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
@@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
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.
@@developerwaypatterns thank you 👍
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.
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.
that make sense, it sounds like the stale closure is unintended behaviour , in fact closure is always stale
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.
Well, there are always multiple ways to solve the same problem. What would you prefer instead of this one?
@@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.
@@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.
@@developerwaypatterns that makes sense. This was really helpful. Much thanks ✨
You are brilliant . Your only lack is you are from Russia.
mind blowing solution
why not compare props.title === prevProps.title && props.onClick !== prevProps.onClick in React.memo() too?
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.
@@Myszko3321dont wrap it in useCallback at all, just skip rerender if it changes
You'll have exactly the same problem as described in the video then, when state inside is not updated