How to Persist Redux State to an API Part 1

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey y'all what's going on we're here with a coding tutorial series to specifically answer the question how can i persist my redux state using some kind of api i have a student in our full stack development boot camp working on their final project it's an in-browser called idle clicking game where you basically select select some options and it will go through and basically play the game for you it's a genre of gaming that's actually pretty cool like idle games and things like that and it's a fantastic and killer final project and they were wondering how to persist their redux state as they're using redux toolkit so obviously if you don't know anything about redux redux toolkit this may be a little over your head but nevertheless hopefully it helps somebody out there and it's a cool video for me to learn something new and try and figure out solutions to it right so uh beginning here i'm gonna go ahead and get my project going and we'll talk while some things install so mpx create react app we'll call it persisting redux so you know i i came across solutions out there such as like oh just serialize and cram it in local storage but you know the student was like okay that's fine it works but what if i for example one of my friends using this game has some progress and they happen to just clear their browser cache one day i want them to lose all their progress and then this individual couldn't find any solid answers out there so that's why i did some digging around and decided to make this youtube series around it this video will be longer than the rest because we're gonna be building out our boiler plate that i'll push to a github repo that should also be in the description this video uh as a starting point for some of our different solutions to this problem so we're gonna have to write out all this boilerplate first and test it and then i'll show you my first solution in this video which is not very much of a reduxy solution but it does work so per sitting should be persisting i'm gonna it's gonna bother me if it's if it's spelt wrong so per sisting redux there we go let's fix that typo first thing and foremost otherwise i'll be losing my mind trying to remember what i call the project okay um you know and the local storage solution i guess i've used it before too and i didn't mean at the time i was building like a character building application for a tt rpg for my friends and i and i didn't google anything about how to persist redux state i was like well if i can just subscribe to the store's changes i can just json stringify them and cram them into storage and call it a day and it worked and then i realized that's what everyone ends up doing so i was glad to know that my what i thought was a hacky solution worked then also you know when my student asked about how do i take that and make it asynchronous work with an api i was like that's a good point because you'd also have to worry about this on react native apps because you all know that you use something called async storage on react native applications but anyway let's go ahead and install a couple things to this project i'll need i'm actually building a very simple express server you don't know much about servers it's okay you can just focus on how i make network requests with fetch to this server but i'm going to install nodemon cores and express to build it out for the front end i'm going to need a redux toolkit and react redux to tie it together there we go these are going to be the installations i'll need for this little starting point of our boiler plate there we go i'm going to open up my code editor and bring it to this monitor because it's on the wrong one for some reason expand it and probably have to zoom in so you all can see okay uh i'm gonna go ahead and create and test the server first thing so i need to do to build my server it's a very simple file i put in the root of my project it's not gonna be very robust again i could also just like make delay promise functions on my react code and to fake and simulate an asynchronous fetch request but i've noticed that i do that for some of my nor newbie students when i do examples like that sometimes they can go over their head of how it actually looks and combines with a real fetch request or network or axios whatever you end up using requests so i'm gonna make this a bit more robust of an example but not too complicated i'm not i'm not building out a database and schema and sql and things like that we're going to simply use a global variable to save and store our react redux state so let's bring in express can't wait till we have a version of l of node in lts let's stop it and talking is hard everybody so i can't wait till we have a version of node that just has import statements and modules freaking figured out finally so i have to keep jumping between these two things and types of statements we're gonna need cores as well cool we're gonna say let's create a new express application our new server this app needs to use core since it's gonna be running on a different port than our react application it needs to use a body parser of some kind whether you choose url encoder or json don't doesn't really matter i'll be using json in this example so in order to parse and create the rec.body you gotta have a body parser and we're gonna listen on port 8080 so it doesn't conflict with react's default port of to 3000 which again if and if i ran this at 3 000 create react apps code is good enough to pick that up and say do you want to run on port 3001 instead uh in this console log i would like to give myself a nice message server listening on port 8080 exclamation point to feign excitement that's a very simple server here it's going to need a couple of routes to do its job i'm going to go ahead and just make this dumb variable called save state we're gonna initialize with the value of null for now and we're gonna go ahead and make two requests a get request to forward slash state that will have the wreck and response callback function is gonna do a magic magic thing of a response json of the save states this is going to respond with whatever state we're trying to save uh this way we can configure our store with some saved state some kind of pre-loaded state asynchronously and we have to have a way to actually save this at some point so i'll make this a post request of the same path there we go res.json [Music] state save some kind of response that we can just google or not google console log for ourselves in the future and it actually needs to save this state with this magic magic magic method like so there we go that way i'll make a copy of that wreck body object i don't ever recommend messing with the request body directly so i always like making copies of it and doing things like that so basically i'm just reassigning that save state variable globally to whatever my rec body coming in is so i'm assuming the request body will have the correct state structure and i can also now retrieve it from that get request a very simple server but but it serves a particular purpose in our package json i'm going to come down yonder and add a server script that will start using nodemon on server.js so if i do have to make any changes to my server it should auto restart and while we're here we're going to add a proxy line that will actually do something for us later on localhost colon 8080. i think because of this i don't actually don't need cores but i like to add it there anyway just to be safe coors is cross origin resource sharing it's saying that if browsers have this coded as a default blocking feature saying if a server is in a different location than your client website that is called a course request or cross origin because the origin of the website is not the same thing as the origin of the server and they will clash the browser will block that automatically but we have cores enabled on our server so we'd have to worry about that here i'm going to clear this out and i'm going to open a second window because we'll need one to run our react application and wonder on the server i'll run the server since it's going to be very simple up top and a smaller window npm run server oh yeah cool listening on port 8080 nothing to it my server is incredibly simple and what it does it has two requests at the app level that simply read and reassign a global variable so i know once i restart the server the global variable is not actually saving anything this would be obviously replaced by a more robust server that you're using or coding yourself and you would probably have a database query using or sql or something like that this is just for demo purposes i'm not getting that far into building a full stack application for this example i'm going to go ahead and open up postman postman's a server testing tool i recommend that y'all get and use it or some kind of other tool there used to be one called where what is it called now there are in-browser ones that you can also use matter of fact there's another one called hopscotch.io that is a simpler version of postman that runs in the browser so that's another option should you choose to use that as your testing tool they work the same fundamental way you open tabs that can simulate network requests to a server these actually also because they're considered server to server don't trigger course requests so localhost colon 8080 forward slash state gets our state variable which is currently null a copy paste to a new tab drop down to post we're going to do a body of json format and this json will be example redux state let's have a redux state that has two reducers we'll have one reducer called off and then one called count coming up here off will have a singular property called logged in whose value will be false and counts will have a property called i keep writing the double codes value of say 5 or something like that who cares this is just test stuff right so that is my json body if i send this request state has been saved if i get the state we are now successfully have written a server that could i mean as long as the server doesn't restart it saves our redux state and then sends it back for one singular person in their app so if we had multiple users clearly this is not going to work again why i mentioned this is a contrived what's my favorite word example that's it okay the job here is done beautiful okay now we're going to cut out some boilerplate and even with redux toolkit there's a little bit of boilerplate we have to write out i'm actually going to remove some of the default boilerplate included with create react app just so i can really focus in on the fundamentals of what we actually need to get this job done all right and like i said the future videos won't have this part in them i'll have this probably pushed to a repo so we all have like the same starting point we can all experiment and figure this stuff out so okay i have two folders one called features one called store or you can call it app according to the redux toolkit docs it's a folder it doesn't matter you can call it pizza it doesn't matter as long as the path is correct to it two features we're gonna have one called off slice it's gonna have the following import where we importing uh called a function called createslice from redux toolkit it's brilliant brilliant stuff we're gonna go ahead and we'll make an initial state variable why not i like doing this personally keep things this will represent my off uh state and if you recall from the json body i was building in postman it was off dot logged in false that's the initial state and now we can actually create it auth slice equals create slice object argument initial state colon initial state little es6 shorthand right there if the property and value are the same you can put them together we need a name for this state called off and we need to have our list of reducers as an object and here we go for auth we're gonna have one called a login login will be a function that takes the current state of off and simply modifies it as such state dot logged in equals true then we'll have one called log out that will simply set togglet to false and again if you're if you're not familiar with redux toolkit redux toolkit has a middleware applied to it called immer immer that allows us to write mutating code and it will translate it into the correct uh the the correct type of code which is that non-mutating like spread operator nested spread operator nested spread operator garbage you have to write in vanilla redux without immer it's very very very nifty folks it's super awesome so create slice has two things it can produce for us a list of actions and a reducer um i'll choose to do it this way export default the reducer from offslice like so and from the actions i will export out login and a logout from actions and we'll have them be named exports and this actually follows a pattern called redux ducks pattern where you export your action create not your action objects but your action creator functions which is what these are and your reducer is the default export from this file redux toolkit follows that duck's pattern beautifully so we'll make the same thing for accountslice.js and to make our lives easy i'm simply going to copy and paste some code over i mean why not let's rename this from off slice to count slice the state will go from a value or for logged in to value starting at zero and we'll have some different reducers we'll have add which will take the current state and an action and it will simply say state dot value plus equals action dot payload so we can pass in a number to increment this value by this count value by copy paste sub sun evidently sub minus equals action payload and then we'll do one called reset just for funsies for practice state i'll simply say state.value equals zero there you go there are our lovely actions creators so we'll add them to our list here sub and reset there we go that is how fast and easy it is to get up and running with the redux toolkit i freaking love it typo there that semicolon doesn't need to be there okay cool so our two slices that's enough slices all right done here sorry i had to throw out that meme i couldn't help it get in the comments if you know what i'm talking about uh throw out our store here index.js we're going to import we can we can do one of two ways we'll do a configure store like so and we need to bring in our reducer so i'll import auth reducer from the features of directory forward slash off slice and then change this one to be the count reducer from the counter slice and you know with a vanilla store we can do it as such con store equals configure store and it needs to have our object with a property called reducer that will be an object of our to reduce reducers right so this is actually something very nifty that you can do in redux toolkit you don't have to combine the reducers because if you simply pass it a property called reducer with the object of your is in it it will auto combine reducers for you which is super freaking cool if you all recall this is what it actually used to look like if you have previous redex experience and you're wondering how this is is it combine reducers should be command reducers i was hoping it yeah it was plural i knew that where you do something like this const reducer equals a call to combine reducers there'll be an object that will be this right here as well as matter of fact paste like that and then in place of reducer you'd have root reducer so we're gonna leave it like this for now just so you know some old heads can take a look at it and be like oh yeah that's what that makes sense that's what it used to look like all right there we go we built out our store it's fascinating i know moving on in our index.js i now need to import that store from the store directory and its index file we're going to import our provider component from react redux and we're going to wrap our app in it and it's so hard not to talk about every little thing i'm writing because i'm actually making and still working and learning and building a react course it here at covalence that covers all this stuff incredibly in depth so if you have interest in that check out the description below go to our website sign up or the very least get involved in our discord community and come hang out and ask questions and code and learn and ask for project ideas the very least do that so there's our provider there's our app matter of fact i don't have an app i deleted it so let's go ahead and bring that back in again thank you for staying through the setup portion of a video i don't like having too many things coded out beforehand in a video because there's so many good learning opportunities coding stuff from scratch even if i'm just kind of rambling while i code like while i write out some boilerplate code but this should be our app and it should be able to access the use dispatch hook and the use selector hook and oh my god these hooks are so so much nicer than the old connect api if you remember what that looked like get in the comments if you remember that hot mess back in the day these hooks make our lives so much easier and a destructure often count this is also a terrible selector if i catch you all doing this in the real world i'll kill you so don't do it uh that's a terrible selector because that means anytime any part of the global state changes the whole app the whole ass app is going to re-render but as we know that's not really in the the scope of this discussion it's more about how we persist state right uh let's do count dot value if that appears in the h1 i know we are set up and good to go let's go ahead and start our react app that was a lot of code to write without actually testing luke so this could lead to utter disaster like it did in the previous take of this video series okay that's what i'm talking about y'all whoo we got a beautiful looking react application right here up and running with redux already added to it when i was a fresh boot camp graduate if you told me i could get redux like applied and up and running into a project in a span of like five to ten minutes i would have called you crazy with the old vanilla redux boilerplate code which i know how to write from scratch now because i have a course built around it so this is awesome right we are good to go to start doing some fun stuff in the app here like we'll say account like that what did with some buttons below this button will say add it'll have an on click event that when the button is clicked it will run this function code to dispatch a adding action we need to import that action from the appropriate feature file from features counterino and it will have the add sub and reset features because why not make this a little bit more fun paste paste this one will be sub this one will be a reset we'll call our action creator reset no payload required we'll call our sub action creator with a payload of one we'll subtract one and then add will you know you guessed it add one there we go up and running oh just kidding right an inner producer return a new value and modify its draft what have i done folks uh boys dispatch add one sub one reset these are all fine it's the reducer i messed up in it is it now well well well well what have you boy done is there some kind of weird i think it's because of the implicit return as mike is my guess ein minutin bitter since i did one line implicit returns i bet it was the imr was producing something weird because of the return because with immer you can actually provide a return statement and actually use like old school syntax or if you had something that looked like this back in the day you would have return your state spread out and then value would be whatever it currently is which would be state dot value minus you know uh action dot payload this is like the type of producers you'd have to write back in i'm wondering if because i did a implicit return on some of these code bases that it messed up in that regard so okay i'm gonna laugh that was the case so my is my short handing is what screwed me yep okay yes that's what it was folks and again i i don't like to edit out my mistakes i like to leave them in because i think it's a valuable learning opportunity to say that someone that's done this for a long time and built a lot of projects with it you never stop making errors guys and gals you simply get better at finding out what you did and how to fix them so es6 shorthand has screwed me in this regard where i again the implicit return from the arrow functions maybe some of y'all already screaming at me when i was doing that was triggering immer to not work the way it was expecting to so there we go nice little fix up right and so i know this is just trivial you know ridiculous things i'm gonna put a fragment in here real quick and we're going to make the same thing for off again i wanted to have like something that was a bit more than just like a counter going up and down so let's have a logged in we need to actually visualize this uh it won't render boolean value so i'm going gonna actually call two string on it so it renders the boolean value we'll have a login button and the log out button we're gonna delete that button need to have the action creators from off log out nope not console log login logout login and this will be log out surprise surprise all right this is what i'm talking about y'all okay and again here's our lovely app it does so many cool things in that right y'all so now the question is how do i persist this state but honestly before we persist to state i think i should probably push it to a github repo and again i know this is kind of long but like i said before i i like having things written and i'll stop the server for now come on now whatever uh new repo we'll call it persisting redux starter create repository on my other monitor there we go initial comb it and push okay so that we will have this in the video description and we run our server so we're back up okay so now this demo is actually going to kick into effect and do something as you can see here we need to have be able to import our store synchronously and apply it as a prop to our provider component you can actually provide some initial state to your redux stores by utilizing a particular object key on the configure store you can find this from the documentation on redux toolkit very easily and it's called pre-loaded state preloaded state is actually very smart and then i can provide i can provide a object and it will properly merge it into my state as long as the properties are the same right so if i now configure this with a pre-loaded state check it out it goes to 10. this is what you would do basically if you're using local storage you would simply say retrieve from local storage the stringified state and then you'd parse it and then simply tell it to use it as a preloaded state so that's fine when you're doing something synchronous and this is where my student ran into trouble going well how would i tell it to wait in some form or fashion before rendering the app to finish retrieving that state to create the store in order to render the application so the first solution is not really a reduxy one this is something i came up with basically on the fly almost instantly because i was like oh just rap that wrapped in a promise homie and it's a really hacky solution but it does work and it does have some drawbacks this is the first solution it's a hacky one but it will get the job done and will look like kings and queens doing it right so uh yeah what we need to do is have some way of fetching that data first and then uh what's it called and then configuring our store with it because that preloaded state bit then the configuration must be synchronous so it's not like we can say hey await this promise then build the store we still have to access it in this file somehow so here we go what i ended up doing that i called a super hacky solution i thought was quite funny in that uh we're basically going to build a configure store async function that slows things down for now let's check out what i mean by this i'm going to go ahead and say the following let's test something first remember when i said write that proxy line into our package json let's remind ourselves since that was like 22-ish minutes ago uh that i wrote this proxy line right here that is the address of my server this way in my fetch request i don't have to write the full address which is localhost colon 8080 forward slash state it will simply proxy to that value for me so let's see if this works here our json and then we should have our pre-loaded states saved from our server but i've restarted the server so i know it lost it so we're going to test something here shall we console log preloaded state to see if anything fires here i'm not going to do any crazy error handling not going to worry about that so let's take a look at our apps console log no that makes sense because currently it is null right uh this is what it's receiving as fetch request so what we're going to do is post with our new state right here and it's going to save that state i'm going to confirm in our get request that it's there now if i refresh the browser it's going to get that new state and voila we now have it and we need this to be their preloaded state so we have to have some way of wrapping the configuring of the store and accessing it still in our root of the application so here we go with our fun utility function i'm going to say export const configure store async and this is going to be a function that's going to return a new promise i teach my students how to do this to build database query utility functions and i am amazed at how many things it can actually help so it's going to resolve a reject with some code what it's going to do is it's going to run this fetch code right here from the cut and paste there we go and it needs to configure and then resolve with the store right that's what we're gonna have to do here so what i am going to do is yeah i can do that i can just say like let's store equal null initially and when the store is built i can simply say assign a value to the store asynchronously called configure store surprise surprise i'm actually just going to do this right here cut and paste there we go and there we go it will configure the store with some pre-loaded state and we'll use es6 shorthand there there we go and now after the store has been correctly configured we can send it out of this promise to use elsewhere by simply resolving with the store once this task has been completed right that's all it needs to do so now that is set up i can import and use it in the root of my project and here's how we're going to do it like i said hacky and fun that's what i'm all about that's what i'm all about y'all from the store there we go so if you didn't know you could do this i mean you could typically technically delay the initial render however you like so uh bear with me what we're gonna do is simply say configure store async when that promise then fires it should return with our configured store asynchronously at which point i would like to then render the app with the provider and the store asynchronously so again this is i came up with this fairly quickly and then after doing some googling i found out that other people also came up with the solution but they're like it's it's kind of new amateurish it's not amateur it's just good stuff it's kind of like hacky and not very reduxing its implementation but it crashes can i read properties of null why did that happen state is oh because it reset yeah so whenever i i think i one point in time when i change some code in react like a root project or a root file i think that triggers my server to restart so clearly you're going to have to write some error handling which i can do here as well state saved refresh yeah so my server got restarted which means my variable got reset which means it had no initial state which means it crashed so we're gonna have to handle that error and i'll do that in this video but there you go watch this if i change this in my save state from 10 from 5 to 10 and from false to true save it refresh the app and then initial render will come with that preloaded state so you clearly want to have some kind of loading render happen initially that will then be kicked off during this process um if you all want to see how to do that we can actually do that from our html file where we have like an event that we fire off from here telling it to stop loading or something like that right but nevertheless this is an easy way to now asynchronously preload your state from an api all in one little nifty tidy video so if i was going to try and handle some kind of error right like meaning if there is no store uh if there is no preloaded states then i don't want to crash the application here's how i could do that i could have something like const options equals an object where i have my reducers is my root reducer so basically i'm building this yellow object right here like this and i'll simply say if there is pre-loaded state coming back from the server meaning it is not null then i would simply say options dot pre-loaded state equals pre-loaded state and now i'm configured with those options in case there aren't any and reducer is required argument oh it's reducer typos y'all there we go so my server restarted again so i'm going to send this state saved refresh voila i'm now going to what am i going to do i need i need to trigger my server to restart so i'm going to restart my server like that now my state should be back to null right get send it is null state that way if i refresh the page it doesn't error out and crash anymore in case there is no save state for this particular user uh with if they're making this fetch request with a token all in all reality so yeah uh that is what i would do to configure my store asynchronously to get this stuff done it's pretty cool you know the next question would be how do i actually save it in real time this is actually another fun little solution that you can do uh we're gonna do an export const we'll call it how about we say uh save state makes sense to me it is going to be a lovely uh another thing that returns a new promise like so it's going to have our resolving and rejecting functions and we don't even use reject we can ditch that if we wanted to but i'm just trying to be consistent here so be a fetch request to forward slash state it is going to have some values inside of its options object because our method is no longer a get request it's a post request it needs to have some headers since we're sending some kind of wreck body with it the application forward slash json content type header kicks on our body parser express.json and the body will be a json stringify of whatever state we pass in we're going to have that be our argument so we're going to say that this thing's sole purpose is going to be to help us console log and see and console.log and see what we're doing here so we can say uh i don't know dot then we'll call it i mean it doesn't matter what we call this is the variable name you know we'll call it resolve res like that there we go that's it what its purpose is going to do is it's going to take this state and kind of save it for us to our server asynchronously so we can keep our index code looking a bit cleaner as well so i'll say bring in our save state i should probably call it async technically it's a better name because that's what it's also doing right that's a better name right that's a better name better than something like pizza or pasta which is just as valid of a variable name and while we're here with the store uh because we are accessing our store here we now have access to all of its methods which you can dispatch functions to it or you can even subscribe to state changes and we can pass a callback function that will allow us to use some async oh wait i shouldn't really mix in taxes of async and dot then i tell my students to be consistent who likes being consistent but we're going to pass it a callback function that will then run our save state async function passing in uh the store state which we can access by running a store.getstatecall that will get the global state of the store uh synchronously and return it to us to our save state function that will then take whatever response our server sends back to us and console log it which if you remember was that uh message that said state saved so taking a look at it now okay seems to be working just fine and if i even if i do empty cache and hard reload our server has the state of the application or this user in the database somewhere saved we would then retrieve that information and then be able to asynchronously preload our saved redux state other solutions i'll be talking about will be how can we do like some html handling if we needed to how we could use a library like redux per sis which had a large gap where it wasn't being maintained so if you see any answers using that library from a couple of years ago they will fall a little bit short thankfully in 2021 i saw in their github documentation that they got some new maintainers like new management is what they called it and actually added typescript to it thank god and it's pretty awesome i'll be covering that in a video to show you how that works there and i will actually show you another way to do this uh with a more reduxy solution where we'll have an app simply run a used effect that will dispatch an action to try and hydrate our store as a term you're gonna get used to hearing as well that's hydrating the state right filling in values from before and yeah that's uh that we're gonna end this video here it's already 34 minutes long but uh this is this is a fine solution like i said it's a little bit hacky and not very reduxy in its implementation right because we're kind of not working with what redux is supposed to be which is everything is dispatched to the store synchronously we're kind of handling that weirdly we'd have to error handle or loading handle our initial render somehow to let our users know something is happening in case our server or their internet connection happens to be particularly slow that day um we'll have to account for that kind of stuff as well but uh yeah this this totally works and it's what i recommend you all start with this is what you're trying to figure out how to persist state um yeah so yeah i mean check the comments below for the github repo if you want this boilerplate as a starting point for practicing or doing things in general uh if you have comments questions or concerns obviously like comment subscribe right get in there get in the comments let us know um follow the link below to covalence.io to sign up for my read react course if you're just here totally curious we have a full development full stack development course as well and i chill on our discord pretty regularly um whether it's on hours or off hours because i just like helping people and i like coding i like learning stuff and there's no better way to code and learn than to work alongside with students at any skill level above mind below mine equal to mine doesn't matter because we all can help each other on this journey that we're all on together so tata for now i'll see you all in the next video we'll talk about a different approach to trying to save your state
Info
Channel: Covalence
Views: 3,426
Rating: undefined out of 5
Keywords: Covalence, Programming, Coding, Software Development, learn to code, online coding bootcamp, intro to react, intro to typescript, node.js, React.js, free web development tutorials, software development bootcamp, web development, javascript, express, become a programmer, how to become a software developer, programming tutorials, become a full stack developer, software careers, redux, persist redux, persist redux api, react-redux, redux toolkit, rtk, save redux state, hydrate redux state
Id: SzrUQLced98
Channel Id: undefined
Length: 36min 1sec (2161 seconds)
Published: Fri Jul 29 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.