React State Management using Context API (useContext + useReducer Hooks = Magic 💥)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey what is up everyone and welcome back to another video today we're going to be looking at global state management in react and we're going to be using the context to do this so let's dive right into it so what exactly is meant by global state management global state is basically state that you make globally available hence the name for any component in the component tree to have access to that state without having to prop drill so let's just take a quick look at this detailed example so let's say you have your application and you're managing your state in the app component in download componentry we have component a component b c d and e and let's say component c and component e needs access to this state this stat can be anything you save in the app component so in this example i'm going to be using is the user authenticated and what is the ui theme and let's say component c and component e needs access to this state in order to render something conditionally or display the state so how would we get the state from the app component down to these two components so the normal way of doing this we will have to prop drill we have to pass each of these state properties down each component as props and this can become very cumbersome especially if your application grows very large and you have a lot of components nested inside of each other then this nesting of components to pass state is not very effective because component a b and d does not even use the the props or state you pass through so it's it's actually an unnecessary step so this is where global state management comes into play so when we talk about context as global state basically we create a component which is this context component and we wrap this component around our entire application component this app component is the root component to all the other children down the component tree so this context component that wraps the app component has access to the global state and manages the global state so this allows this context component allows each of the children component to have access to the global state without having to prop draw so now each one of these components c and component e can just connect to the context and read the necessary state that it needs from the global state so this is how global state works and this is the main idea behind what we're going to explore today so now that you understand exactly what is meant by global state let's dive right into the code and see how this works okay so there are two especially important hooks to understand when we are working with the context as our global state and these two works are use context and use reducer so let's just quickly take a step back and look at two small implementations of each one of these hooks how they actually function and how they are used so that we can understand how the combined effect between with the two of these hooks help us create this global stage manage global state management workflow so let's start with the use reducer hook so the use reducer hook is basically the exact same as the use state hook which is used to manage state inside of a component but the use state is more for simple state management for like changing or two-way binding in a in an input input element all those type of stuff use reducer on the other hand um is more used for complex states so if you want to do more changes with one different action use reducer is a better option for this so let's take a look i have a very basic example here i have a use reducer example all of this code will be linked down in the description for the github and i'm just going to run through what i have here so this has no functionality as of yet so i can press these buttons and nothing will happen so what the idea behind this is is we have a count state that we want to manage but we want to be able to input a variable and then initialize this count value and then by pressing this buttons we can increment and decrement this count value so let's take a look how this will work so firstly what we'll do is we'll go at the top we'll import use reducer the hook from react and then we can initialize this we can destructure it array destructuring and this will give us two things it will give us state and a function called dispatch and then we can set this equal to the use reducer hook and then we pass in two things to this use reducer we can pass in um the reducer function so reducer function i'm just naming this the reducer function you can name this whatever you'd like and then some initial state i'm just going to call this initial state so at the top we can go and create these two things i can say cons producer function is equal to an arrow function and this arrow function takes in two parameters the first one being state and the second one being some type of action and we'll come to the body of this function just in a second then the second thing we passed in was this initial state so i'm just going to call this initial state and this is going to be an object that contains our count value we want to manage so now we can pass this function is passed in right over here and this initial state is passed right in over there so this reducer function works as follow we usually do it in a switch statement and we will dispatch this dispatch function we'll dispatch different actions to this reducer function to manage or handle the state in different ways so let's start action.type so this is going to check the type and let's say the type the the type of this action that is dispatched is increment and when we get this action of this string identifier we want to spread the state that is passed into the reducer function and then we want to manipulate the count inside of the state so we say state dot count plus one so this would increment this initial state that is passed in over here so now we can do the following or decrement so we can say decrement and do the same we will return the new state we spread the current state you don't have to do it with only one variable inside but it's just good practice to remember to do that otherwise it doesn't mutate you will overwrite the entire state so you can say state dot count minus one and then usually with a switch statement we default the value for in case none of the string identifiers were used so we'll just send back the state and do nothing with it so now we have finished the use reducer function that we have passed to this reducer hook user reducer hook and now on this dispatch function that was destructured from this hook we have access to this reducer function to manipulate this state right over here so let's quickly bind this state to our buttons so if i say on click right over here and on this on click i want to activate some anonymous function that dispatches a object that contains a type because in this reducer i'm looking for action.type so this action will be sent from the dispatch and the dot type will be will be set right over here so we can set this type equal to increment and then we can do the same for the decrement part we can dispatch the object of type equilibrium just like this so if we save this and go back we can see it's still zero but this is not the zero that is initialized in the state because we hard coded the zero in here so now in this state that is destructured from the use reducer we have access to that state so we can say state dot count and if we save this it should give us zero as well so now we have zero there as well so now these two buttons should increment and decrement the state so if i say increment we can see that the counter is counting up if i decrement we can see the counter is counting down but now let's say i want to send some value to the state and update it based on whatever that value is we can do that as follow i have a label here that says starting count and then input for the for the user to type in a number and then i just set the on change onto this use state right over here so let's get started with that so once i press this initialize counter button i would like to send off a different action so this action we can create in the in the switch we can say a net count for initializing the count and we can return the current state we spread the current state and then we take the count value and set this count value equal to the action dot payload so this action once again is whatever is dispatched and this payload will set on the on the dispatch value so here where we set the type value we can add another dispatch or payload value this is you'll usually see this in redux which is also state management so let's see if this works so on the button we'll also have a on click and here we want to dispatch an object of type we named it a net count and we can pass to this object another key value pair called payload and in this payload we pass in the input value so this input value is equal to this use state input value that it just binds this count counter so with this done we can check it out in the browser we can initialize the value to 15 and there we can see the state was updated to 15 and now i can press these individual dispatchers to manipulate the state so this is basically the workings of use reducer so the next took we're going to look at is use context so let's dive into that so what exactly is context context is a way of sharing data so this is how the the global side of the context as global state comes into play so the reducer is more to manage and manipulate the state where the context is used to to be wrapped around um all of the components that needs access to this this specific state so what i have here is a really simple application i'm just quickly going to run through what i already have here it's just a basic application context example this would be on github as for the previous one and it's just two links with the react router dom which links to two different components so the first one is the the home component and it only says this is the home page and then the feed feed link just takes us to the feed page so it's really simple but the idea behind this is we want to have some state that is available between both of these components so let's dive right into how the context works so when i use context i usually go into my source file and i create a new folder called context so that i know all of the the context state or things i want to share is in this folder so i go and i create a app dash context dot js file and in this file i create my context so this is three lines of code this is really really simple and we do it as follow we say import some value from react and this value is create context it's literally in the name and then we create this context so we can say const app context is equal to create context so this we just import it and we initialize this as a function so we can pass in here some initial value if you click on it and do it like so you can default any value so we're not going to do that but you can enter any default value you'd like and then we just export this variable app context so now we have access to this context in all of our application where we imported so this is the first part the second part is in the context file we create our state so i call this app state dot js and this should be in capital letters because this is going to be the component so here we can just use the snippet array fce and create a functional component and here we'll import this context we just created so we name this app context and in capital letters because we're going to use this for a component and we import that app context now when we return we don't return this dev we will return the app context and on this context we give it a provider and this is what i said in the example previously this provides all of the components in the componentry access to this values we're going to place in this context so then we pass in as prop to this component some value object and inside of this object we can share state or we can share different values so i'm just going to hard code a value in here called message this is from the context and i'm going to import the props because this is going to wrap all of the app component so in between this jsx returned component right over here we just insert the following props dot children so this will allow all of the wrapped components to have access to this value or whatever is inside of here so let's test this out with this done let's go to our app component and we will import this app state app state from the context folder and then the app state file and now we use this app state as a component which it is because you can see this app state is just a functional component that has the context as its jsx that is returned so now we can wrap whatever we'd like to have access to this values with this component so we would like the following two things to have access these two routes so whatever is routed also has access so these two components that are rendered the home page component which is this one and then the feed component which is this one so we're going to wrap the switch statement with a app state component just like this and if we save this and we go into each one of these so we'll go into the components and we'll go into the home component and here we would like access we want to print that message inside of the sp tag so in order to do this this is where the use contact hooks come into play so we can say at the top we can say use context and then we import this context so that three-lined piece of code file so we can say app context from we'll go outside into the context folder and import that app context file and now we use the hook we can say const and destructure anything out of whatever is in use context which is that message variable and we pass this app context so now we are telling this hook okay we want access to this app context and this app context is created in here so this gives us access to this so with this done we can destructure out of the app context this message that was passed into the app state so we can destructure this out by just doing the simple line we now have access to that message value so we can print this message value out in the p tag and if i save this and i go to my home page i can now see this message being printed out just it's as simple as that i can see this message being printed out now we can do the exact same for the for the feed page so now we can share different state between this so i can do something that manipulates the state from the home page and it will update and be shown inside of the feed page so let's quickly make sure it works in the feed page as well so i'm going to close the home page it's exactly the same as as with the the home page go into the feed page we'll import the use context hook and then we'll import the actual context that was created and then we'll initialize this use context so we can say use context is equal to that app context and this will be destructured object is structured because we pass in an object so we can get that message here as well and save so now i can once again add a b tag over here and just place that message right inside there like this so now on both of these pages i have access to that shared state from a different component so this is very powerful so let's quickly um dive into another bit more if we want to render something conditionally so inside of my context i'm going to create state so i'm going to import the use state loop inside of because this is just a normal component and we can use anything in here later we'll use the use reducer and this will enable us to create this state management system so i'm going to set this auth equals to false so i'm going to destructure this array destructuring and inside here i have this auth and set just like this so now i can pass this is off variable into my value so i can say is and this value is equal to the is auth up here just like this so i can actually because of es6 i can remove that and just pass that in so now when i go to my home page i want to render this homepage color based on if is auth is true or false so now i can go into the home page and i can say where this div i can once again get access to this is auth by the same context and i can style this div based on i can say background color based on that variable from the global state background i can say is auth if if this is true i would like to set the background equal to green else set the background equal to red so if i save this we can see it is red now because the value of is auth in the app state is actually false so if i set this to true now and i save we can see it turns to green so this is amazing way of handling state globally it's not inside of the actual home page component but you can handle it now now you can do different things i want to render if it is authenticated i want to render a button and that says log out and what this button will do on click we want to change the state from is auth from true to false so in order to do this we have to go to our state and pass in this function that is passed from the u state into our value as well so i can say set is auth so you can see it's a different color it's it's this orange color this means it's a function that is passed through the context as well so we can even pass that functions through the context which is amazing so now we can go in in here and destructure that is auth and now i can use that right over here set is auth and i can set this equal to false just like this and if i save this else if this is the case and it is not true i want to render a different button and this button will be a login button which just triggers the set state once again the set is auth state so i want to do this again but i want to set this equal to true and we can name this login so if i save this we can see it is currently logged in because it's green and it renders a log log out button so now i can say log out and it turns it red and it renders a different button so this is how we can globally share state between components and manipulate this so with this out of the way we are really on the way to understanding in great detail how context can be used for global state management with the use reducer hook and the use context hook so with this out of the way let's go check how this will work in a bigger application together okay so now that we are done with the use reducer hook and the use context hook and we know how they work let's combine them into this very basic to do application so in this application i'm going to go a bit quicker through through the code because i've already explained some of the nitty gritty stuff so basically this is just a simple to do application i will be able to type in something here and say add to do and then it would add it down here below i just added a dummy one so we can see how it looks then i would be able to toggle the to do complete or not complete and it will change the text color and then it will be able to delete the to-do so it's really basic so let's dive right into it i'm going to start just going through what i have here i have a to-do input which is this top part over here it's this is its own component and then the bottom part here is the to-do list component and inside of the to-do list i have a to-do item which is this rendered component right over here so let's start by creating our context so once again i like going into the source folder and creating a context folder and inside this context folder i usually start off by creating four context files so in this epic application because it's only one context we're using i'm going to put everything in files inside of the context folder otherwise you can break it down into different folders as well for different types of context so let's start i'm going to make to do dash context and make this js file and this is just going to be that three lines of code so it's going to be import from react and we're going to import create context and then i initialize this in a variable create context and then i export default like this and just export the context so if this is done we can save and we are done with this file we can close this we can close the app one as well and inside the context folder i'm going to create another file and i'm going to call this to do state dot js and this would be the actual contact context component that is going to be rendered so i'm going to say r-a-f-e create a functional component and i'm going to import the context i created so i'm going to call it do context with a capital letter because i'm going to render it as a component and then i can place it in here say to do context dot provider and insert the values so for now i'm not going to have any values in here i'm just going to do it as follow we'll get to the values in just a sec and then just add the props dot children just like this so with that out of the way we are done with the state and i'm going to create another one and i'm going to call this to do reducer doj so i like naming my separating my reducer and my context because this kind of gives it a redux like feeling and redux has really good best practices to follow so inside the reducer if you remember from the use reducer it's basically just a function so we can say const to do reducer and set this equal to a function and this function will take in two parameters and this will be the state and some action and then we'll have a switch statement that will be used to check the types of each action and then we'll just export this function export default to do reducer to do reduce it just like this so with this all done um we are pretty much well on the way so we don't have to import this other this by accidentally imported so the last thing i like to do is create in the reducer when we dispatch the string identifiers i like to follow the best practice of creating actions so to do actions.js and here i create constants um that just helps for making the string identifiers easier to import and manage between the reducer and the context so here i can say um add to do you're going to have some string identifier to add it to do so i'm just going to copy that exactly into this right here so in the use reducer example i this would have been increment and decrement so i'm just setting it equal to this variable so i can get ide functionalities to just import this so i don't have to worry about spelling mistakes so another one is going to be [Music] toggle the to-do and the last one is going to be export cost delete to do like this okay so if this done i'm done with the actions so now i can use these actions and import them inside of my reducer so i can say import something from the to-do's actions so now i can pull out of those actions i can say add to do see i get ide formatting for it toggle to do and they need to do so now i can go and check for the following things i can in case it is add to do i can do the following i'm not going to do anything now because we have to set up the state first i'm just creating the boilerplate and then we can check for toggle to do and then return the state and then i can check for delete to do and then check for and then manipulate the state and then the last one is the default and here i will just return the state like this so our reducer is almost done let's go back to our context let's go back to our context component we're creating and in here we use the use reducer hook to reference to this use reducer so we can use reducer get the importer hook from this to do state so this is where the context is being used so in here we can import this use reducer and we can import this reducer file so this one over here this function which we export down here so we can say um to do reducer from dot slash the reducer file just like that now we can use this use reducer and give it this um give it this to do reducer so inside of this function i can create my initial state and set this equal to to do's which is just going to be an array of to-do's and e-to-do will look like this we'll say it has an id and it this will be some number and then it will have a text which would be some text which specifies it to do and then we'll have a complete key value pair which will be set to false initially and this will toggle if it is completed or not so this is how individual to do will look inside of the array so now we can create this use reducer so we can say use reducer and pass it in that reducer function the to do reducer and this initial state and this will destructure into an array const and we'll get two things from it we'll get the state and we'll get this dispatch function and it's important to name it like this okay so once we've done that now we're almost basically done so we're going to want to have three functions that we place inside of these values so in the value we already can put in the to-do's and this to-do's will come from this state because remember now we are using the use reducer to manage our state so in the previous example of the use context we had a use state inside of our to do's and we just passed that in so now we're going to use this state so in order to get this to dose which is passed in as initial state here we can say state dot reduce and then the three functions we're going to need is one to add a to do the other one is to toggle add to do and the last one is delete to do and you can create one for editor to do but for simplicity and for length of this video i'm not going to do that so now we can create this we can set the const um to do is the function name just making an error function and this function will receive the actual to do which will send from the from the the to-do input okay so here we'll only do one thing we'll dispatch this function over here and we'll dispatch to our reducer object which has a type and here we can impose import those string identifiers as well so we can import from action to do actions and we can import the add to do the toggle to do and the delete to do so now i will dispatch the type of ad to do and i will give it a payload of that to do i get in the function so wherever i would call this function inside of my application i would pass it some to do and this to do i will pass as payload to my reducer to add it to my state so this should make sense from the previous examples of how this flow works and this would be the same for toggle to do but instead of getting the actual to do we get it to do id which will compare to the state id over here to determine which one of the to do is in the array we have to toggle this complete for so here we'll dispatch the type of toggle to do and we'll just you can see the ide um formatting it gives me which is pretty helpful so i don't have to type in myself and i'll pass in as payload this to do id i got from the function and then the last function is the delete function the lead to do function which also will only take in some id and here i'll do exactly the same i'm just going to copy this dispatch over here and it will be exactly the same except for the string identifier will now be delete to do instead of toggle to do with this done i have all three of my functions that will dispatch my types and my payloads to my reducer now i just have to give my contacts access to these functions so i can pass them in down here add to do you can see there orange toggle to do and then delete to do just like this so now the final step to do the final step to do to get this um context to our application is to wrap our entire application with this context state so we're going to import the to do state which is this component and then we're going to wrap our application in this context so you can say context to do states or not this one to do state just like that and now we can wrap our entire application that needs access to this um to the context in this to do state component just like this so if this out of the way we're basically on the way of completing our application as i said i'm going really quickly if you don't understand you can just go through it again slowly but it should all make sense after the other two examples so now that we are done with our um context i'm just going to make this smaller our context we are pretty much done here we have our state which is basically only this and let's see okay that's all good all good okay so with that done we can close this up and we can go to our reducer function so this is where we have to think about how the logic will work when we have to add a to do toggle it to do and remove it to do so let's first add a to do and see if that works so we get the state which is that initial state variable that is passed into the use reducer in the context file or in the app state file so here we spread the state and then we go to the to do's array and we want to add a new array with a new to do so we create an array and we spread the current to do's so this is how the spread operator would work we'll spread the current reduced the same as this we'll spread a new array with the current to-do's that is already in our to-do's array and we'll add the new one that was sent on the action.payload so we can say action dot payload so this will have the new formatted to-do so with this done we are basically done done with air to do so let's see if this works so let's go to our input to do input file and over here we want to use the context now so we firstly have to import the use context hook and import that context file so we can say to do context from outside completely like this and we import this to do context then we initialize this context by saying array destruction use context and we pass it this to do context just like this and now we can pull out all the functions or all the things we need for the input so for the input we only need the add to do function so we can just pull it out like this add to do now we have access to this add to do and what this application does basically it has a form with on submit and this on submit function is called up here and basically all that happens is we take the to-do that is currently in the use state up here so just what's inside of the text box the two-way binding then we want instead of console logging into the console we want to call this add to do function and pass it the to do but before we do that remember how to do has this format where it's some id and some text and then some complete which we set to false initially so we have to format it here before we send it to our function so let's create that new to-do and this will have an id we're just going to set this id to math.random and then we're going to set the text equal to whatever is in this to do which refers to this input so this input's value will be equal to the to-do so we set the text equal to the to-do and then the complete will automatically be set to false because when you first create it it's obviously not completed and now this new object we created we pass that into the ad to do and that would be catch by the context in this function and then dispatch it to the reducer so let's go check out if this works so um we have this current one in here okay firstly remember we are not loading the to-do's from our context so let's go into the to-do list into right over here and here where i load this to do item i want to get access to the to-do array in our context so here we're going to do exactly the same we're going to say use context and we want to import the context so import to do context this is really repetitive but it kind of brings the the muscle memory and the point home of how this would work so then we initialize the use context like this and we pass if the to do to do context then we object the structure out and what we're going to need in this part of the application is um a few things basically all the other things we're going to need the to-do's we're going to need the toggle to do and we're going to need the delete to do because we're going to put a on click listener on this component to toggle and delete the to-do so now we got the actual to-do's from our context so now we can do the following and say to dos.map and for each to do i want to create a to-do component so i can do this as follow to do item and this item if we go and check what this item gets as props we would like the following things we would like the the text and then yeah that's basically that so we can destructure this as the text and save this and go here and just place in the actual to-do text right down there and here we can pass it that text this text will be equal to the actual to-do dot text and then when we create in this map function individual component each component should have a key to help react re-render the the dom correctly in the virtual dom so we can say to do and pass it that random id so now we're basically almost done there's only two more things we need to do here is pass it the toggle and the delete so we're gonna have a click when we click on this application on this actual to-do we would like it to fire off some different functions so i'm going to call this toggle or let's say click toggle click to and then another one click to delete like this and then we'll pass in a few things so before we do these two let's just quickly check if this works so i'm going to save this i'm going to go back to my application and you can see it's empty right now so if i enter something here make bed and i just spell correctly and i add it i can see make bed was added to my to-do list so this is awesome there's no area checking so if i were to add nothing and it would create a blank one but you can check that on your own so now we want to handle the to-do and the toggle so i'm just going to close up all of these we actually have to still open the reducer i haven't finished that yet so let's go to the toggle and delete to do in the reducer so right over here we once again want to spread the state so if we think about what we want to happen let happen when we toggle it to do is we go into the to-do's in this state and what we do is we say state dot to dos dot map so we want to go through each one of the to do's and wherever the to do the current to do that is mapped its id is equal to the action dot payload so you will remember we send the to-do id from the reducer function that is dispatched in the action payload so if this is the case i want to spread the current to do so i want to recreate that current to do and i want to change its complete value to whatever the current to do's complete value is so if this doesn't make sense um i would suggest pausing and trying to understand what happens here so we spread that current to do so this to do that is mapped over we take everything inside of it and place it inside the new object then we go to that complete object key value pair and we switch it we negate it from what it currently is so if it's true we make it false if it's false we make it true otherwise we just return the to do so it's as simple as this doing a different operator is very very simple otherwise you have to do some if and recreate it like this once again and if we want to delete a two we once again spread the state and for this it's important to spread the state because otherwise you don't get all your other to-do's back so here i want to use the to-do's and i want to say state dot to do dot filter so now i want to filter through all of the to-do's and if that to do i'm filtering on is equal to the to the id i pass in as dispatch i don't want to add him into the new array so basically filter creates a new array which will help us eventually remove the actual value so i can say here if this to do dot id is not equal to the action dot payload i want to add him i want to return so everything that's not equal will be added to the new array the rest will be left out so if i save this and i am basically done now i can leave that closed i can go to my to do items and on this buttons the toggle and the delete i want to add on click and here i'm going to get something from the props which is going to be the click to toggle and click to delete functions so i can just pass them right in like this and this should be on click one as well and then pass it in like this so with this done i can go to my list and this should be the last things to do and add a click to delete and pass it there toggle delete toggle to do function in right here so we're going to create a function anonymous function and this function will run this and then we'll pass it in this current to do that is being mapped it will pass it its id so we can pass it in like this and then we'll do the exact same thing copy this and paste it in alongside but instead of deleting we'll add the toggle i see i added the wrong function to the wrong one here so i can actually just change this to toggle and keep this as delete and then just pass in the delete to toggle just like this so now i have the delete and i have the toggle so in order to see the difference in the toggle and the difference in the toggle of complete we go to the actual item and we render the text of the span so this spans text dynamically so we can say style is equal and now we can pass in if it is complete or not so we can pass it in the complete and here we can say to do dot complete so now we have access in this to-do item to the complete or to check if this this item is actually complete so you can use use context in here as well to check this but because it's only one level deep it's easier to use it as props so here we can say the style so the color should if complete it should be equal to green else it should be red just like this so if this done we can go back to our application we can say make bed and it is red if i toggle it it's green back to red like this if i want to delete it i just press delete and it's not there anymore so make bed create video just like this both of them are red just like this breakfast and then i can delete them all the way so this is how the use reducer and use context is used to create global state management in react i really hope you found this video helpful and if you did please remember to like subscribe and leave a comment down below and then i'll see you in the next one cheers
Info
Channel: The Full Stack Junkie
Views: 19,816
Rating: undefined out of 5
Keywords: State management with Context API, useReducer hook, react hooks, react hooks tutorial, react hooks explained, advanced react concepts, reactjs tutorial, Reactjs, Global State in React, React State, useContext and useReducer, useContext Hook, state management in react js, context api react, react context api, react state management context
Id: zxP4oGejqpU
Channel Id: undefined
Length: 50min 26sec (3026 seconds)
Published: Tue Aug 18 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.