Being a React Native developer, selector-related performance issues are usually the most impactful yet the hardest to diagnose and detect due to near terrible debugging experience. These issues scale exponentially the more screens + components you have nested in the stack, so I'd say this video caters even more so to us, native developers, than the web developer dudes.
Flipper helps to bridge the gap a bit more by giving you access to Redux Devtools in React-Native. Doesn’t help you diagnose everything, but definitely better than nothing if you haven’t used Flipper before.
I personnaly use reactotron with reactotron-redux in order debug my app, but indeed it might not be perfect for debbugging the performance of the useSelects().
I am very impressed with the quality of the video on your channel regarding optimization and state management, sir. become a self-taught front end and managed to get a job in 4 months studying through youtube, blogs and udemy, I am very sure, that your channel is the king of optimization and state management
Sir, being a React developer, I must say that's high-quality content, and you've amazingly explained the foundational concept of useSelector. Love it...
would be great to have full guide video how to set up single-spa to have microfe with monorepo on existing microfe react. Basically, imagine we have microfe monorepo build with module federation to support communication between packages and we want to migrate that monorepo to single-spa
Really nice video, I think I've watched all your content during the last couple of months. I noticed that you returned the numbers array in the updateSecond reducer in zustand as well as in redux. I believe you already taught us we only need to return the items actually updating in the state when using zustand :)
@Abhilash M I think you've got it. As long as the `numbers` reference doesn't change, then you won't get the re-render. That's what you are looking for, selecting down to primitive types (preferably) like strings, numbers and booleans. Or selecting specific keys if you have arrays or objects within a store object.
When i saw the title i thought you would bring the react-tracked lib, which has been brought in this channel before to fix the context api but which also has solutions for both redux and zustand
Hey Jack hope things are well with you and your family. Wanted to drop a comment and say thank you for the work you have done within the React Community. You have helped me become a much better React developer with the various videos and articles you have created. It has opened my eyes to more effective approaches to engineering React applications, thus helping myself and the company I work for solve problems in more effective and optimal ways. So again thank you very much it's greatly appreciated. Keep up the great content!
The same issue occurs if you create an object in the useSelector function and return that object. I tripped on this when using a single useSelector to select data from the store and return a view specific object.
First of all, great explanation! I have one more question here. On the app I’m working on currently, we have a Zustand store that contains an array of nested objects. How would you suggest to handle this? By using shallow to detect changes in the first level of the objects, it would still be „too deep“ to not render the component as it would again compare objects.
Assuming that you are working on changing just one entry at a time. Just create a new array with the contents of the old array (that would copy the references), then create a new object for the one you are editing, with the contents of the old object, and make your changes to the new object and replace the existing object in the new array with the new object. Or... use immer.
I have been destructuring useSelectors all over my app, so you're saying that my app becomes much faster if I'm not so lazy and use non destructured items for ALL of my values? I got some work to do 😳
Hi Jack Herrington. I love your content. can you pleas some day make a video about how to structure the folders in a react app, I have struggled a little bit to find the perfect one.
Can React.memo prevent the re-render of children components - where the parent component is subscribed to a nested object via zustand/redux? i.e., the parent component is an array of deeply nested objects, and a child component is a consumer of said object.
Thank you for your explanation. I really love it. But I'm a little confused about when does useSelector function run. It runs when every action dispatched?
Yes, all the selectors are run every time the state is updated BUT that does not mean they force a re-render by setting state. That only happens when the selector return values differs as described in detail in the video.
Hi Jack, I wanted you to make a video about when SPA application grows, how we can maintain that, as we start we have some components our bundle file would be less but as our application grows we would be adding more and more components, and our bundle file would be increasing how can me make sure our bundle files would not be grown as time goes, Thank you, so much for your videos It really helps a lot in my career
I'm very impressed by your comparison of the two. I would say Redux Toolkit is more suitable for large projects and complex business logic, while Zustand can become messy over time due to its 'free-for-all' nature
Great video and really good to know about this! Still trying to get Redux toolkit to play nice with Next.js ssr here never got state management to work as showed in your next.js state video 😭
This is an awesome videos.. Could you please make a video of an app which is a victim of such bad usages and how should we debug them? Keep up with the great content😊✌️
Jeff? I'm Jack. But assuming you meant me, it's about references. Arrays and objects are compared by reference and not by contents. So if the contents change but the reference doesn't then neither React nor Zustand count that as a change.
@@jherr It’s the autocorrect on my phone is weird, Actually what my actual question was that example if you have a state like currentUser, which is an object and it has a key whose value is also an object (currentUser is anested object I mean) now if I use shallow function which only check 1 level deep, then here as key ‘s value is object which means shallow will return false even though that key’s value is not actually changed !!
@@jherrwhat if I do this const { currentUser, numbers } = useStore( (state) => ({ currentUser: state.currentUser, numbers: state.numbers }), shallow ); Here even though I use shallow because as the object keys are array/object as well, then it will rerender 🥲
@@ayushjain7023 Question for you. Does this re-render? const currentUser = useStore(({ currentUser }) => currentUser); const numbers = useStore(({ numbers }) => numbers); If it doesn't then why do you think that's the case?
@@jherr Sorry Jack, I should have been more specific in my question. I Apologise. What I meant to ask was, in Zustand I saw you can write your own middleware, is it possible to achieve the same thing you did using a middleware rather than adding the "shallow " param in multiple places? or is it not a good idea to use that approach? Thanks
@@dg3152 Is there a middleware pattern in a different state manager that does this. This question feels kind of "trappy". Like you already know an answer. Two ideas though, first, you shouldn't have to do shallow compare because you shouldn't be creating new objects or arrays if they haven't changed their contents. Second, you could use middleware to keep an associated changeIndex value for an array or object. The middleware would do the shallow compare and bump the index on a true change. Then you could select the object but compare on the index in the getter.
So, every single `useSelector` that's currently mounted has a cache of its own? Wouldn't that be a memory hog for large applications? Image N mounted components, with say M `useSelector`s for each.
By cache do you mean the storage of data to compare it to the last value? A value in this case is either just a value in the case of a primitive, or a reference in the case of an array or object. I'm assuming you are concerned about copies of big arrays or object structures? That's not an issue because it's just caching a reference to that structure and not a copy of the structure. In general, React apps are very memory intensive. Every single tag or component invocation in a React component is a call to createElement, which creates objects and stores them in a massive VDOM. And on every re-render more objects are created and compared again to that stored VDOM. It's a massive amount of memory usage and churn that is just inherint to the system.
I love how you say Zustand 😂 nothing against your content, it's great, as always 🙌🏼 Zustand is the German word for state. You could use Google translate to get an idea on how to pronounce it in german 😁😂 but I'm fine with your pronunciation, continue using it, since no one really cares about it 😁
Yes. If you use a "selector" atom, then the result of that atom will only force an update if the `oldValue !== newValue` so you should try to select down to primitives (number, string, boolean). Unfortunately there doesn't seem to be a comparitor function option on `useAtomValue` to allow for a shallow check (or something else). So... that's problematic. Love Jotai tho.
Sir, stack of technologies I am using in my project are next.js(typescript), tailwind, twin.macro and storybook but I can't just make them work together perfectly Well I somehow did make them work together with some issues but honestly I don't know how I did it 😅 So can you address this issue Love your content by the way
I do have a Discord server if you want to jump on there and post your question in the #react channel maybe you can get some help to figure it out. Please follow the #rules before posting.
Being a React Native developer, selector-related performance issues are usually the most impactful yet the hardest to diagnose and detect due to near terrible debugging experience. These issues scale exponentially the more screens + components you have nested in the stack, so I'd say this video caters even more so to us, native developers, than the web developer dudes.
Flipper helps to bridge the gap a bit more by giving you access to Redux Devtools in React-Native. Doesn’t help you diagnose everything, but definitely better than nothing if you haven’t used Flipper before.
I personnaly use reactotron with reactotron-redux in order debug my app, but indeed it might not be perfect for debbugging the performance of the useSelects().
I am very impressed with the quality of the video on your channel regarding optimization and state management, sir. become a self-taught front end and managed to get a job in 4 months studying through youtube, blogs and udemy, I am very sure, that your channel is the king of optimization and state management
Sir, being a React developer, I must say that's high-quality content, and you've amazingly explained the foundational concept of useSelector. Love it...
Excelente video, gracias.
More zustand and typescript tutorials please 🙏
I got the knowledge of reading a 100 blog posts.. in one video😁.
Thank you very much
Nice.......didn't know useSelector depends so heavily on how you get stuff out of state but it does make total sense. Great explanation.
Lucky to have found your channel. Was trying to find good videos explaining the use of zustand and yours was definitely comprehensive. Subscribed!
would be great to have full guide video how to set up single-spa to have microfe with monorepo on existing microfe react.
Basically, imagine we have microfe monorepo build with module federation to support communication between packages and we want to migrate that monorepo to single-spa
Really nice video, I think I've watched all your content during the last couple of months. I noticed that you returned the numbers array in the updateSecond reducer in zustand as well as in redux. I believe you already taught us we only need to return the items actually updating in the state when using zustand :)
Yeah that’s true. GitHub copilot added that destructure and I should have removed it.
@Abhilash M I think you've got it. As long as the `numbers` reference doesn't change, then you won't get the re-render. That's what you are looking for, selecting down to primitive types (preferably) like strings, numbers and booleans. Or selecting specific keys if you have arrays or objects within a store object.
Mr. Jack, amazing explanation! You also showed how to switch to other state managers easily. 👍🏻
Extremely useful for state management with redux, thanks Jack.
When i saw the title i thought you would bring the react-tracked lib, which has been brought in this channel before to fix the context api but which also has solutions for both redux and zustand
Hey Jack hope things are well with you and your family.
Wanted to drop a comment and say thank you for the work you have done within the React Community.
You have helped me become a much better React developer with the various videos and articles you have created.
It has opened my eyes to more effective approaches to engineering React applications, thus helping myself and the company I work for solve problems in more effective and optimal ways.
So again thank you very much it's greatly appreciated. Keep up the great content!
Thank you!!!
High-quality content as always ❤️.
do you have same video on preventing unnecessary re-renders when dispatching actions?
The same issue occurs if you create an object in the useSelector function and return that object. I tripped on this when using a single useSelector to select data from the store and return a view specific object.
I love how you made redux easy to understand, goin with zustand though
First of all, great explanation!
I have one more question here. On the app I’m working on currently, we have a Zustand store that contains an array of nested objects. How would you suggest to handle this?
By using shallow to detect changes in the first level of the objects, it would still be „too deep“ to not render the component as it would again compare objects.
Assuming that you are working on changing just one entry at a time. Just create a new array with the contents of the old array (that would copy the references), then create a new object for the one you are editing, with the contents of the old object, and make your changes to the new object and replace the existing object in the new array with the new object. Or... use immer.
A pleasure to learn from you, thanks for contributing so much to the community!
I have been destructuring useSelectors all over my app, so you're saying that my app becomes much faster if I'm not so lazy and use non destructured items for ALL of my values?
I got some work to do 😳
Great content! One small thing: shouldn't store be named as store.ts instead of store.tsx because there is nothing to render?
Hey, Jack!
What do you think about Zustand best practice?
What do you prefer single store or many stores?
Many stores is what I've done and I'm good with it. I don't think a singleton store is ever a good idea.
Hi Jack Herrington.
I love your content. can you pleas some day make a video about how to structure the folders in a react app, I have struggled a little bit to find the perfect one.
Hi, Very informative video :), Could you please walkthrough us from your setup of recording and also How are you writing on screen. Thanks in advance
Your explanation is very detailed. thank you very much
awesome, you really go deep in production level code, normal we just see abcd of things, but you go till xyz
Can React.memo prevent the re-render of children components - where the parent component is subscribed to a nested object via zustand/redux? i.e., the parent component is an array of deeply nested objects, and a child component is a consumer of said object.
this video thought me more than 6 to 7 hrs of entire course. your videos are really awesome. keep up the good work
Hey man great vid, we have a high impact on our app performance due to redux, this helps us solve it, thanks a lot!!!
Thank you for your explanation. I really love it.
But I'm a little confused about when does useSelector function run.
It runs when every action dispatched?
Yes, all the selectors are run every time the state is updated BUT that does not mean they force a re-render by setting state. That only happens when the selector return values differs as described in detail in the video.
Thank you, Jack.
Revisiting this now! Great content as usual! Thanks for sharing, Jack!
Thank you for watching.
that means it's fine to use shallowEqual in every selector we call?
Great content as always. This is the video I've been looking for!!! 😄Thanks
If Shallow fixes unnecessery rerenders and the shallow function is exported from the library it self then why its not so already by default?
Because it's less efficient.
Hi Jack, I wanted you to make a video about when SPA application grows, how we can maintain that, as we start we have some components our bundle file would be less but as our application grows we would be adding more and more components, and our bundle file would be increasing how can me make sure our bundle files would not be grown as time goes,
Thank you, so much for your videos It really helps a lot in my career
Great vidoes! Best content in TH-cam for React developers!
Loved this, how do you go about authorization using Zustand?
Great video! In zustand, how do I get multiple values from the store so I can destructure them using the state pick?
Use the selector function to select them out into an object and then use the shallow compare, destructure the object on the other side.
@@jherr Okay, thanks!
so cool, thank you, Jack. Now I know it's called Referential Identity.
One word, Magnificent!
I'm very impressed by your comparison of the two. I would say Redux Toolkit is more suitable for large projects and complex business logic, while Zustand can become messy over time due to its 'free-for-all' nature
I disagree. I've seen lots of Redux stores that have become a junk drawer of state on the idea that "everything needs to be in the store".
Does react-tracked or use-context-selector libraries from daishi kato work like this too?
I’d have to check but my hunch is yes.
Great video and really good to know about this! Still trying to get Redux toolkit to play nice with Next.js ssr here never got state management to work as showed in your next.js state video 😭
Why are you SSR with heavy duty state management? Wouldn't you want CSR for a more sophisticated app?
@@Euquila its one complex app that need seo for dynamic data and state management for tons of data and my sanity 😵
This is an awesome videos.. Could you please make a video of an app which is a victim of such bad usages and how should we debug them?
Keep up with the great content😊✌️
zustand is like saying to you "Relax bro, just focus on your stuff, i'll take care the state for you." which how all state management should be.
This is pure gold
Hey Jeff, why it only compare one level deep what if numbersarray have objects instead of numbers that does not change ?
Jeff? I'm Jack. But assuming you meant me, it's about references. Arrays and objects are compared by reference and not by contents. So if the contents change but the reference doesn't then neither React nor Zustand count that as a change.
@@jherr It’s the autocorrect on my phone is weird,
Actually what my actual question was that example if you have a state like currentUser, which is an object and it has a key whose value is also an object (currentUser is anested object I mean) now if I use shallow function which only check 1 level deep, then here as key ‘s value is object which means shallow will return false even though that key’s value is not actually changed !!
@@ayushjain7023 Huh, that's weird. If you have something like:
const user = { name: "Jack" };
const settings1 = { user, someState: 1 };
const settings2 = { ...settings1, someState: 2 };
Then:
user === user // true
settings1.user === user // true
settings2.user === user //true
@@jherrwhat if I do this
const { currentUser, numbers } = useStore(
(state) => ({ currentUser: state.currentUser, numbers: state.numbers }),
shallow
);
Here even though I use shallow because as the object keys are array/object as well, then it will rerender 🥲
@@ayushjain7023 Question for you. Does this re-render?
const currentUser = useStore(({ currentUser }) => currentUser);
const numbers = useStore(({ numbers }) => numbers);
If it doesn't then why do you think that's the case?
Very insightful. Thanks.
Hi Jack, can we get more videos about backend development? Technologies such as node js, express, databases such as mongodb, mysql and more...
lovely as always
How do you do annotations on the code itself
Screenbrush
Hey Jack, thanks for the tutorial! How would you implement this using middlewares and persist ❓
I don't understand the question. This is about selectors. It doesn't have anything to do with middleware or persistence.
@@jherr Sorry Jack, I should have been more specific in my question. I Apologise. What I meant to ask was, in Zustand I saw you can write your own middleware, is it possible to achieve the same thing you did using a middleware rather than adding the "shallow " param in multiple places? or is it not a good idea to use that approach? Thanks
@@dg3152 Is there a middleware pattern in a different state manager that does this. This question feels kind of "trappy". Like you already know an answer.
Two ideas though, first, you shouldn't have to do shallow compare because you shouldn't be creating new objects or arrays if they haven't changed their contents. Second, you could use middleware to keep an associated changeIndex value for an array or object. The middleware would do the shallow compare and bump the index on a true change. Then you could select the object but compare on the index in the getter.
@@jherr I think I understand now! Thanks for all your content! It helps me a lot!
What are you using to paint on screen?
Screenbrush with a drawing pad
So, every single `useSelector` that's currently mounted has a cache of its own? Wouldn't that be a memory hog for large applications? Image N mounted components, with say M `useSelector`s for each.
By cache do you mean the storage of data to compare it to the last value? A value in this case is either just a value in the case of a primitive, or a reference in the case of an array or object. I'm assuming you are concerned about copies of big arrays or object structures? That's not an issue because it's just caching a reference to that structure and not a copy of the structure.
In general, React apps are very memory intensive. Every single tag or component invocation in a React component is a call to createElement, which creates objects and stores them in a massive VDOM. And on every re-render more objects are created and compared again to that stored VDOM. It's a massive amount of memory usage and churn that is just inherint to the system.
@@jherr Thanks!
Thank you, Jack. ✌️
thanks for sharing this you help me a lot 💙
Why should we use these state managers over react context api?
Because of the flow
but what if you include all the components into single one?
One mega-component for the whole app? I've seen that and it's a bad idea.
I love how you say Zustand 😂 nothing against your content, it's great, as always 🙌🏼 Zustand is the German word for state. You could use Google translate to get an idea on how to pronounce it in german 😁😂 but I'm fine with your pronunciation, continue using it, since no one really cares about it 😁
Jack you are a great person with awesome content please can you make a video on caching
Is it Zustand like German for state? In that case you would pronounce the st in Zustand like st in state :)
Great video as usually. Thanks a lot!
Yes, you are correct, I'm letting my pronunciation of it slip lately. :(
@@jherr it's not important at all, just wanted to let you know :)
@@bagorolin No worries. I should get it right though... Respect for the language and all that.
Ty Jack!
What theme are you using ?
Night Wolf [black] with JetBrains Mono.
So helpful, thanks a lot :)
Does Jotai "suffer" from the same issue?
Yes. If you use a "selector" atom, then the result of that atom will only force an update if the `oldValue !== newValue` so you should try to select down to primitives (number, string, boolean). Unfortunately there doesn't seem to be a comparitor function option on `useAtomValue` to allow for a shallow check (or something else). So... that's problematic. Love Jotai tho.
how do we solve the problem of objects inside array [{name: 'rohan" ,class: '10'}]
Thank you Sir
Well explained 👏
Cool!
Super bbbbbbb thanks sir
terminal autocomplete???
Great content but you stopped too soon. I would like to see section on handling nested objects and array of objects.
Fair point. Perhaps I'll do a followup. Some kind of "How to manage arrays of object in React" type video.
great vid ! Btw it's spelt "efficient" ;)
Its great
Sir, stack of technologies I am using in my project are next.js(typescript), tailwind, twin.macro and storybook but I can't just make them work together perfectly
Well I somehow did make them work together with some issues but honestly I don't know how I did it 😅
So can you address this issue
Love your content by the way
I do have a Discord server if you want to jump on there and post your question in the #react channel maybe you can get some help to figure it out. Please follow the #rules before posting.
@@jherr will do that Thanks sir
Cool
Is anyone curious about reactformbuilder?
Kwaka?
quokka
ж, д, дб ??? =) 1:39
Jack, please checkout $mol js FE framework
nicd 😊