React Context vs Redux - Who wins?

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hi and welcome to this video should you use react Redux or react context or HD context API killing react Redux and these are questions you see quite a bit and here's my take on that and will actually take this application here which uses redux right now and for which I'll walk you real quick and could word it fully to the context API so that you can see for yourselves if it's worth it if you like that approach and if it's better than redux so here we have a little demo application link of forest below the video and this is a very very very very simple shop which has basically a few products here which you can add to the cart and you'll notice a lot a slight delay here as I do add them if we have a look at the cart we see them here also with a quantity being updated if we um remove them or add them we have a slight delay in there basically to just simulate that we're also talking to a server I could have added a spinner or anything like that but it's not so much about the UI here but about the functionality speaking of that if we have a look at the code what I got in there is I'm using Redux so I'm setting up my store here in the Enix J's file and we'll have a look at these redux files in a second let's first of all dive into the app I got my app.js file in which I do set up my router my react router here I have two routes one for the products page and one for the card page if we have a look at these routes well essentially in a products page I render a list of products which I do get from redux with map States you brought two props in the main navigation which is a separate component I do pass my card item number because I do show that card item number here next to my cart link in the main navigation so here I received that as a prop and I do pass it in from both products and the card page in the cart page I get my cart items with map state two props and I then render my card items here and I got some styling and so on now I do you assume that you know the basics about redux otherwise you probably wouldn't be wondering if context is better than that just to give you a brief refresher on redux and how it works here in the store folder I have my Redux actions because Redux is all about dispatching actions which then changed at central store because in its core the idea the important thing about read access that you have one central store in your application which you can then tap into from different parts in your app if you want to change it your dispatch an action if you want to get something out of there you use this map stage two props approach I'll come back to in a second so I got actions in Here I am using redux funk setup here in index.js when I create my store here and that essentially allows me to execute async code in my action creators which are these functions where you could reach out to a web server or as I do it here you set some time out to simulate an API call as I do it here and then after the timeout I do this patch my ad product to card or my remove car a product from card action now these actions are being dispatched from inside my app they are made available to my components with map dispatch two props and map states two props and map dispatch two props these are functions I defined here which I can pass to that connect higher-order component which in turn is made available by the react Redux package and this is essentially how you connect a component to the global Redux store this allows you to tap into it and get data or dispatch actions to it so this is how this flow of data is if we have a look at the reducer which is essentially the function getting executed when an action is dispatched in that reducer I have in here I do have an initial state with some dummy products here in the initial state and then that reducer function here I do a check for my two action cases add product card and remove product from card and then I just update my card array here to either add an item if it isn't in there already or if it is in there already I just update its quantity and that is essentially what I do here and the same for removing feel free to go through that in detail you do have to code after all so this is a classic Redux set up let's now convert this to the context API which is a feature built-in to react because right now read acts of course is a third party package I did install react Redux here and I installed Redux and redux func some free extra packages to add this functionality and of course that adds to our mandal sighs so if we can get rid of that with a reasonable effort it might be worth it because we ship less code to our users if we find ourselves writing a lot of extra code we might not be doing that though so let's find how much effort it takes now the idea behind the context API in reactors that you can provide context which essentially is just a JavaScript object you could say you provided at some point in your app could be in your route app component could be in an average component and all child components off the component where you provided in then have access to that context so they have access to this JavaScript object you provide this is kind of the idea of that central store and Redux just a bit more flexible because if you want to have one central context you can do it in your root component in your topmost component or if you will only need state in a part of your app you provide that context in that part by providing it on a component a little further down in your component stream so here I actually want to have a global state and therefore what I'll do is I'll add a new folder context to kind of kind of differentiate it from my store folder and I will add my shop context JS file in there now I want to create my context object in this file so that I can then import it into the different parts of my app where I need to access it so how do we create such a context in react well we can simply import react from react first of all because the context thing is baked into react so we need to access it on the react object and there we have a create context function now create context this function takes a default value as a first argument so we can pass in a default JavaScript object and I recommend doing that because even though you don't technically need it as you will learn and at least not in this example if you add it here you get better auto completion in your IDE which is definitely worth it now in the end the data I want a store here is of course still the same data as before I need my products and my card array so we'll just copy that here from my store reducers file and move it into this object which I'm creating here now using the context in this file would be nice but not really it's not really what we need to do we need to use this context from outside this file we want to use it in our other components so let's export this as a default by simply adding export default in front of that created context now we can import from that file and let's import in the app.js file where I want to provide that context because in all child components of the app J's file even if they're loaded by routing I can thereafter tap into that context so in here let me import my shop context and you should import this with an upper case starting character because we'll use it like a component from and now let's point at that context folder and then the shop context file in there to now provide that context you basically wrap your components that should be able to access it with shop context or whatever you named it dot provider you do that here around my in this case this routing setup so that all the loaded components loaded through these routes can tap into that now here comes the cool thing you can now set a value here and this is the day that the concrete data that is passed down to all these components now obviously I do set a default value here right I do set this default value so it wouldn't need to pass a specific value just to have that but of course we don't want to stay at this default value we want to change that over time and therefore here in app jeaious we of course don't just have to set some static one-time initial value this is the value which when we update it will be passed down to the child components and we'll update those as well so therefore here in my app component I can now use my internal state the default state I can have in any class-based component and the same would be to review use hooks you can then do this with the use state hook so here I'm using the class based approach here in this state I can now again let's say start with this initial setup and therefore we could of course remove it from that shop context file or start with an empty products array here too to just have the auto completion because now I will initialize this here in this state in the App J's file and in here I also now want to add my add product to cart method where I get the product as an argument let's say and I also want to add my remove product from card method where I get the product ID and that do something so essentially the methods I previously had in my reducer here now these functions are added to the app trace file and of course that as I mentioned before it doesn't have to be the app.js file it is the file where you want to provide this context and you of course you can have multiple contexts in one at the same app so you don't have to have one gigantic context in here just as you can split reducers in a Redux setup you can have different contexts which are provided in different components you can even create wrapper components to not clutter your app component with all the logic so use regular react features to split that as you want here I'll stay in the app.js file and I do have my two methods here and in my value here I will now pass in a JavaScript object hence the double curly braces first pair sets up by dynamic value inner pair then creates a JavaScript object and I want to pass down my products which refer to this state products I want to pass down my cart which refers to this state cart so to my state values and now comes the fun part I want to be able to call these methods from inside our components so from the components that receive my context to make this possible I just have to add references to these methods into my context object down there so besides passing products and cart I will now also add add product to cart and you can name this whatever you want and this should point at this add product to cart so it should point at this method important don't execute it here you don't want to run it immediately when this is parsed instead you just want to pass a reference so that this is executed when add product to cart is called from inside a child component just as you would pass a reference to an onclicklistener for example now I'll do the same for removing so remove products from Carville point at this remove product from cart also without parentheses now to get better order completion I will also add this to my default value here add product to cart and this year will just be an empty method which does nothing and I simply added here to get better Auto completion that's all so remove product from card as added there as well and I do get my product here though and here I will get a product ID and with this setup added we got our core state setup now let's add some functionality to add product to card and remove product from crowd so for now it will simply console.log adding product and basically just oops output my product here and do the same for removing so that we can see if that was triggered correctly so removing product with ID and then here we can concatenate our Product ID so now we should be able to see these console locks but of course for dad we now need to access that context from the child components because we're still working in the app j/s and the root component only let's start with products where we want to add our product to the cart first of all I will get rid of connect down there this is a react Redux thing and we don't need it anymore so I can get rid of that you could now delete map State to props and map dispatch to props all commented out so that we have it here for reference but we won't need it anymore instead in here in the products page we now want to access our context the way let me comment these unused imports out as well so we want to use our context in here and now we have two ways of tapping into the context both ways require us to import our context so let's do that first I'll import my shop context and you can name it here as you want doesn't have to have the same name as an app trace because it still will point at the same object I import my shop context by going up into the context folder and then to the shop context file now method 1 of importing it or of using it is that we use it down there where we returned J as xcode for this component and you can use this in a functional component as well you use your shop context and then add consumer we had dot provider in app j s here we can add dot consumer we wrap our entire J's X code with that and in there we get a so-called render prop which means we have a dynamic content in here which will be a JavaScript function that should return the JSX code we want to render for this component so what we previously had returned in our render method we add us now here in this function we have between our and curly braces like this and there we receive context as an argument and this refers to our object as we pass it here into the provider so we have access to exactly this object in our products page now and this means that there for example where I want to output my my cart item number number I can now tap into my context get access to the cart and use the same logic I had down there here I had this reduce function add to calculate the quantity of items so let me bring that up there comment these parts back and of course so now what I have here is my main navigation gets the car that number which in the end taps into the context they are into this card array and reduces this array to a single number that indicates how many items are in the card by adding the quantity of each item and starting with a quantity of 0 of course now this is one part we also want to go through all our products and for this here again we just use that context argument we're getting here the era can access the products because if you have a look at the app tray as file we do have a products field on our context and then we can read all the values in there and of course here I want to add a product to the card so I can just use context add product to cart because I have the add product to card function here or method here in my context object if we save all of that we go to products and reload this page let's open our developer tools in the JavaScript console and let's click Add to Cart and you should be seeing adding product and then this Gaming Mouse here or the plastic bottle so this seems to work as you can tell and this is now using the context API only in the product page thus far hence we see no update here in the cart we also haven't added any logic to really do something on the cart here in app jeaious now I also mentioned that this is only one way of adding the context here with consumer the advantage of this approach is that it works in both class-based and functional components the downside is that this only gives you access to the context in your render part where you render your JSX code if you need access to the context in component it mount or in the constructor then you're lost at this will not work there so let's have a look at approach number two in the cart page again I want to access my context I want to use it so let's import shop context from and go into the context folder and import it from the shop context file and now instead of you in context shop context consumer which we could do let's use an approach which will only work in class-based components not in functional components we can add a static property to this class-based component by adding the static keyword and then this property has to be named context type important this requires react version 16.6 or higher it will not work in lower versions you set this equal to shop context so to the context you imported behind-the-scenes react will now connect to this context and give you access to a special this context property which is made available by react which gives you access to that context object passed down through this context now if you have multiple contexts you want to access in this component you need to get creative and for example create some wrapper components or anything like that so here we now have access to this context which means we could now also use our context in component did mount for example so if i added this year and i console.log this context if I save that and I go to the card component indeed here I see my context object being locked with the default products so this is a pretty nice we now don't have to use context consumer down there instead here where I want to get that card item count well instead of using connect here we can get rid of that and therefore instead of using math dispatch to props and that's the maps tied to props I can again use this reduce function on my card and use it up there and access this context whoops dot card reduce and comment this back in just as I did before but now not with the consumer but with this context made available by the static context type here and I can do this anywhere where I need data from my context like here where I want to get my card items now I can access this context card because here I did rename it to card items whether us redox it's all in that card array we have in a context though the same down there this context cart allows me to tap into the items that are in the cart if I want to remove an item I can execute this context remove product from cart and here I do pass in that ID I want to remove with the bind method now let me remove the unused imports here as well and if we now save this on the cart page we of course have no items in there to see if that works so let's finish this up by going to the reducer and there in my ad product card case this essentially is the logic I now want to copy and add to app KS to my ad product to card function in there so in here I will create a new constant updated cart and updated item index there I want to access my current card from this state and I no longer get an action with a payload instead here I do get my product as an argument I do expect to get that and I can access the idea on that since every product has an ID in this application I then do update my cart by pushing a new item on it if this item hasn't been added to it before and instead of action payload I just pushed a product I'm getting as an argument I set the quantity to 1 there and if I had this item in the cart already I just increase the quantity now let me all to copy the logic for removing an item here from the remove product from cart case let's copy all of that go back to you AB KS and in remove product from cart I'll add this here add a Const keyword in front of updated card and in front of updated item index here we access this state cart and we do get our product ID as an argument here now then we update the cart in both cases I now want to update the state of a purchase because this is where I manage that data I do pass down through the context remember here I'm just accessing my state to get the data a pass in my context object hence I need to update the state of this component to update what I passed down with context so here in add product I call this set state and I set card here to my updated card I don't need to touch my products there because I don't change them here and remove product from card it's the same I just said my card - the updated card with that I should have logic in there that works so let's save all files if I now click add to product I got this instant update because I removed that delay I'll riad it and in the cart page we see it there as well now if I add more gaming mouses here we see that it's grouped together and I can remove items that all updates correctly also in the header now to reintroduce that timeout you don't need a special middleware for that as you needed it for Redux you can simply add it here in the function that executes so an Add to Cart at product two card if you want to make sure that this happens only after a small timeout you can just add set timeout here and do your state update only after that time of course this is just some dummy code in reality you would not set and a timeout you would be making an HTTP request at the beginning and then update your state and the then block or anything like that so let me do the same here now for for removing a product from the cart let's X let's add a function that will execute after these seven hundred milliseconds and with this tiny change if I go back to products now you will see it doesn't update immediately in the header it takes a short while because of that delay I did add but I've read and added of course works the same so that is the context added here the context replacing Redux we could now remove that store folder all redux imports we can now remove redox funk redox and react reacts from the package and we therefore have way less dependencies to achieve basically the same downsides would be that if you have a lot of global state you will end up with a huge app component or you create a dedicated component that holds your state and passes it down as props to the component that wraps and the app component would be that wrapped component and that could then remove logic from your app component let me actually show you that for that I'll add here in the context folder I'll have my global state component you can name it whatever you want and in there we can import react and component from oops from react like this and then I want to add my class global State and you can name this whatever you want doesn't have to be named global State and here I extend component and in my render function I now just want to return this props children so whatever I pass between the opening and closing tag off the global state component when I use it the interesting part is that I will now add the logic I had here in app jeaious for the state and these methods here I will cut that from app J's and add it to the global state so that all the logic is in here and I will export my global State of course as a default in that file so export default global state and now we have that logic in the global State in app j/s I now can remove that shop context import and instead here in global State I want to import shop context from the shop context file which is in the same folder as global State because here I will actually now not just return this props children but I will wrap that robber I will wrap it with shop context provider because you have to remember that the provider provides it's the context which I have to pass here through the value to all its children and if I now use that global state as a wrapper around my AB component or around whatever I have here then still all the child components there have access to that state but that logic for that state is now not packed into the app component but out sourced technically the result will be the same but it gives you cleaner code and allows you to split your code more elegantly so that is possible with the context so the downside of having a big app.js file isn't really there let me show you how this would work I now just need to import my global state component from the context file and there from global State and then I will cut my value object here because I needed in a second but I can then wrap my router here with global state and also close that here so now I'm wrapping my router with just global State an in global state here that value I passed to my shop context provider is that object I just cut from app jeaious where I refer to the products and cards state of the global state component and where I add these methods and global state is really just a normal react component right I do extend component I just use it as a wrapper component to do all that state management and have all the state management code in there so that my app component can stay lean and with that a lot of talking if I save that and the app reloads it still works as before because we didn't change anything logically just make our code a little bit easier to read so should you always use the context API then well on the first look it might look like an obvious answer sure you should it's relatively easy to use it saves you the extra dependency and therefore probably also shrinks your bundle size and why wouldn't you use it if it's baked and to react well let's have a look at quote from someone involved with the development of react and therefore certainly someone who has some insights into what happens behind the scenes and there we learn that even people in the react team are not convinced that you should use the context API for high-frequency updates for low frequency changes like the user picked a different theme the user locked in or at user changed the locale off that application it might be great but due to the way the context API works internally where react essentially has to traverse the entire tree off components it constructs to detect state changes and handle them roughly speaking because of that it's not ideal to use the context API with a global State for high frequency changes so you should definitely not store every keystroke made by a user in their context API now that of course does not mean you should never use the context API use it with care use it for low frequency updates so for state changes that don't occur multiple times per second and definitely consider it for these use cases maybe you can store and were handled the higher frequency updates differently with props or inside of your component then you still might not need Redux and the thing where you would have used it otherwise can be replaced with the context API but if you were building an app where you're storing a lot in Redux and amongst all that state and data all the things that change frequently in cases like this you might consider not using the context API for that but stick to Redux because the context API is really just not built as a replacement for Redux that's not its core idea that is not the reason why it was added to react and therefore don't use it for this but consider it for the use case as I mentioned before mostly low frequency updates and there it's great to use and definitely a great replacement for Redux
Info
Channel: Academind
Views: 193,034
Rating: 4.9391789 out of 5
Keywords: react, react.js, context, context api, react context, redux, redux vs context, react context vs redux, context vs redux, react redux
Id: OvM4hIxrqAw
Channel Id: undefined
Length: 31min 31sec (1891 seconds)
Published: Tue Feb 19 2019
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.