How To Build A Full Stack Nested Comments System
Skills:
LLM Engineering85%Prompt Craft80%Advanced Prompting70%Prompt Systems Engineering60%Agent Foundations50%
Key Takeaways
This video demonstrates how to build a full stack nested comments system using Prisma for database management, Fastify for server-side development, and React for the frontend, with a focus on setting up the backend, database, and React frontend, and implementing features such as error handling, API calls, and client-side routing.
Full Transcript
in this video we're essentially going to create a complete clone of reddit's comment system where you can create comments edit and delete your own comments like different comments and most importantly you can reply to comments in an infinitely nested system which is way harder than it looks this project is a great intermediate to advanced level project that includes database work back-end apis and a front-end react project so it includes everything you need and is a great project for your resume [Music] welcome back to web dev simplified my name is kyle and my job is to simplify the web for you so you can start building your dream project sooner and today we're going to be building out this comment system that you can see on the right hand side of my screen and it's a very involved project as you can see i'm currently logged in as the kyle user so i can edit and reply or delete my own comments as you can see i can edit and i can delete this comment if i want but i can't change the comments by sally for example i could come in here and say you know new reply click post and you can see that reply shows up i can like different things i can unlike them it's very similar to how reddit's comment system works and like that threaded nature minus a few of the extra features of reddit because we're really focusing mostly on liking replying editing deleting and nesting to different comments this is going to be a very involved project but it's going to look just like this when we're done also one other thing i do want to mention about this project is if we go into this client folder over here on the left hand side i just have a boilerplate react application set up i've deleted almost all the files the only thing i added in is the styles.css i'm not going to be covering the css in this tutorial it's mostly pretty straightforward i mean these styles are not anything really that special so if you want to follow along exactly just go to the github link in the description down below and that's going to have this css file that you can find it's inside the source folder here called styles.css just use that css file plop it in import it right here in your index.js and that's going to work just fine you're going to get all the styles that i'm using in this video i just don't want to cover them because it's really not pertinent into the actual important information in this video now with all that out of the way let's actually get started with this project and the very first place that i want to start is going to be on the actual server i want to set up my database for how i'm going to structure my comments my likes and so on what we're going to do is we're going to go over to our server we just cd into that folder by saying cd server and i want to run npm init dash y that's just going to initialize a package json file for us just like this and now we need to download the dependencies we're going to use in this project so i can say npmi dash dash save dev because these are dev dependencies and i want to install prisma and nodemon prisma is what we're going to be using for our database and nodemon just allows us to automatically refresh our server every time changes are made now if you're unfamiliar with prisma i have a full crash course on it i just released it's going to be linked in the cards and description for you to check out now we can see we have those installed so i can create a script here called dev start and that's just going to run nodemon server.datejs whoops just like that so if i create a file called server.js whenever i run that devstart script it's just going to run all the code in our server.js file now the next thing we need to do is actually start working with prisma so we need to install the prisma client so we can use it so we'll say npmi and we want to install the at prisma client and that's going to allow us to actually use the prismacode we generate and now with that installed all we need to do is actually set up prisma so we can start working in prisma so to do that we can just run npx prisma init and that's going to initialize a prisma project for us and if you can see over here we now have this prisma folder as well as this.env file so this prisma folder we can just expand this here so we can really see what we're working with this prisma folder here we have our schema this is where all of our information for our models of our database are going to go and then our env is going to have our url for our server so in our case it's going to be a postgres url and we're just going to change these values so for my particular database url we're going to have this say postgres here and the password is just going to be password and this is running on localhost port 5433 and the database here i want to call comments just like that so this is going to be my own personal url to a local database running on my computer you need to already have your database running before you put in the url here otherwise it's not going to work so make sure that you create a database with this particular url before you put it into your project now with that done we can move over into that prisma schema file and if you don't already have the extension for prisma installed in vs code you're going to see a bunch of weird formatting so just make sure you install this prisma extension so you get the correct formatting and with that said now we can set up all of our different models so we're going to have a model for a post because if we go over to this application you can see we have like a post one and we have a post too and we can see all the information for that post stuff so we need to be able to have a model for post and we need to have a model for the comments that are going to be in those posts so we're going to have a model for our post which is going to have an id i'm going to be using a string for my ids and that's because i'm going to be using a uuid so our default is going to be a uuid just like that next i'm going to have a title for our post which is going to be a string and we're going to have our body of our post which is also going to be a string pretty straightforward as you can see we have a title up here and we have the body down below it now before we set up our relations for like comments that are inside of our post i want to set up just all the rest of our default models so we're going to need a model for our user because obviously users are going to be the people that are making comments so our users are also going to have an id which i'm just going to copy over the information they're going to have a name which is going to be a string and that's all the information we care about when it comes to a user now we can focus on our comment model and this one's going to be much more complex because this is where all the complexity of our application lies so first inside of here we're going to have an id and i'm trying to again copy that id information down and we're also going to have a message that's essentially what your comment is that's going to be a string and i also want to put in here a created at and an updated ad date so we could say updated at and those are both going to be date times and one interesting thing is by default i want this date for createdot to be now so by default when i create a comment they created that date is going to be set to the current time and this updated ad i essentially want to be set every time we change our model so we can use at updated at and that's going to automatically update this time stamp every time we make changes to our comment so that's setting up all that information for us and now we can actually focus on the more complex parts which is hooking up all of our different relations between comments users and post and we'll get to likes after that so our comment is going to have a user that made the comment so we know we're going to have a user which is going to have this user type and if i just click save immediately it's going to automatically populate a bunch of code for us as you can see it added the comment to our user we can change this to say comments just to make it a little bit nicer to work with so each user has multiple comments that they have written and on our comment it has a user which is relating to that by the user id which it automatically generated down here we can do the exact same thing with post so we can say each comment is also going to have a post just like this click a save here and you can see it auto populates all that information for us and up here we can just change this to say comments because each post has multiple comments now in order to get the actual nesting portion of our comments to work we also need comments to have an optional parent id so we can come in here and say that we're going to have a parent and our parent is going to be a comment but this is optional because obviously a root comment such as this comment right here doesn't have a parent because it's just a child of the post it doesn't have a child or parent comment above it so we're going to write that in like this if we click save it's going to somewhat pre-populate our information but it's not going to be perfect so first of all right here this should say parent id instead of comment just so the name lines up with our actual row right here and this should say children instead of comments because these are the child comments now the next thing you'll notice if we just put the parent id into here again is we're getting an underline here saying there's an error and the reason there's an error here is because we have two references to this comment table inside of the same table so we need to give them names so we know what they are referencing so we can say here instead of a relation this is going to be the parent child relationship that's the name we're going to give it and for this comment it's going to be the exact same relationship we say parent child so now we've essentially linked these two things together we're saying hey this parent id right here is pointing to this array of children inside of this comment and again if this is something you're confused by make sure you check out my full prisma crash course it'll be linked in the cards in the description for you this is covering all the information about prisma in there so that this should be relatively easy to follow now one other thing i want to do real quick is i want to make it so that any time that we delete for example a user it automatically deletes all the users comments as well so we can come in here with an on delete and we could just say we want this to cascade and what that's saying is anytime that we delete the thing that this points to which is our user delete all the comments that that user had as well same thing here if we delete the post obviously if there's no more to post all the comments for that post no longer matter so delete all of those comments and same thing here if we delete the parent comment delete all the children comment inside of that because obviously they have no parent anymore now the last model i want to cover is going to be for our likes so we can just come in here we can create a model for a like and a like is really simple it's just going to be a user and a comment because a user is going to leave a like on a comment so this is the only two things we care about so we have our user and we're going to have our comment and if we give it a save it's going to automatically pre-populate all that information for us now you will notice we're getting a bunch of errors with this model though and that's because we don't have an id we could come in here and we could you know create an id but instead of creating an id i'm going to create a joint id because we know that a user id and a comment id are always unique because a user can only like a comment one time there can never be more than one like that has the same user id and the same comment id so we can say that the id is just going to be a combination of our user id and our comment id and that's going to make it so that it's guaranteed that you can never leave two likes on the same comment if you're the same user and we also can make sure that we do that on delete cascade for both of these because again if we delete our user or we delete our comment get rid of all those likes they no longer make sense now with that done we can click save and that's all of the model information for our database done creating the actual database model itself is fairly simple because there's only four different models and they all are pretty basic models the hard part is going to be when we start implementing all of the logic around these models so now that we have this done what we can do is we can run npx prisma migrate dev and what that's going to do is it's going to create a migration on our database that essentially changes our database to look just like this as you can see here and it's going to ask us to type in a name for this so we can just type in a name of init for example because we're initializing our database with all this information and now our postgres database that's on our computer running has tables for a comment it has tables for like and has tables for users and so on so we have all of that information built into our database i guess one thing i do want to change is i want to change this to say likes instead of like so i'm going to run another migration because i made changes to my schema i need to create a new migration so i'm just going to type in that migrate dev again it's going to run and now it's just going to make minor changes to have this say likes instead of the capital like like it was before and i think that's going to look a little better also i guess i'm going to do the same thing here with this likes so i'm just going to run that migrate again one more time just so that those names are consistent across our entire application and you will notice when i do this migration it's not actually making me rename my file to a different name and the reason for that is because changing this doesn't actually change our database itself it just changes the code that interacts with our database our javascript code so we don't need to create a new file that runs on our database that's why it's not asking me for a new file name so now with all of that done now we can actually go in and start working on our server before we start writing our server code though there's one other database related thing i want to do and that is seeding our database you can actually make it so your database starts with data inside of it by seeding it and to do that prisma is really easy we can just create a file called c.js and in the c.js file we can put all of our code for seed in our database so in our case all that i've done inside of here is i've just deleted all of our existing data for posts and users i've created two users named kyle sally i've created two posts which just have a boilerplate post one and post two title and some random lorem ipsum text and then i've created three different comments this is a root comment and this is a root comment and then this comment right here is nested inside of one of our root comments and all of these comments are on post one so we have two posts and three comments and two users that we're creating automatically whenever we run this file now to hook this up with prisma so we can automatically run this file and our package json we need to add essentially one section so we can come in here and we can add a section called prisma and inside this prisma section we need to add a seed and all this seed is is just going to be a command that we can run so that command is just node prisma c.js so we're just saying hey whenever we seed our database run this command right here and this command is just pointing towards that file we just created so now i can run npx prismadb seed and what that's going to do is run that prismacet file we just created because we linked it up right here we are getting an error though the reason for that error is we're using the normal import export syntax that's from es modules and by default node doesn't support that you need to tell node in your package json by specifying the type that your type here is going to be module we're just saying hey we're using es6 modules you know that's what we're doing so now if we rerun this command hopefully this should work just fine no problems as you can see it says the seed command has been executed so now all of this information for creating this default data it's been added into our database so now at least we have data to play around with in our database now in order to run our server we need to download certain libraries so we can type in npmi here and this is going to be for installing our libraries and we're going to be using fastify as our server of choice it's very similar to express but when it comes to creating apis fastify just makes it a little bit easier which is why i prefer it so we're going to install fastify we're also going to install something called env which will allow us to pull in environment variables into our project and then we're going to install essentially a bunch of different plugins to fastify so we're going to start at fastify slash cookie that's for dealing with cookies so we can have user authentication we're going to do at fastify slash course this is going to allow us to communicate between our client and our server and if you're unfamiliar with course i have a full video covering exactly what it is i'll link in the cards and description for you also we're going to have at fastify sensible and this just makes it really easy for us to send errors down to our user so now we can just hit enter and that's going to install all those different libraries what we can do on our server.js is actually get started on our project so in here is where we're going to set up our fastify application which if you're familiar with express is going to look almost identical so to get started we can just come in here and we can say we want to import fastify from fastify just like this and then what we can do is we can create an app variable by running that fastify function this is identical to express up to this point now to listen we can say app.listen and we just need to pass it an object and this object has a port and this port here for example could be like 3000. now it's going to run on port 3000. now i don't want this port to be hard-coded instead i want it to come from an environment variable so we can say process.env.port and if we just come up here and we make sure we import.env from dot env and we run that dot env.config this is going to load in everything from our dot env file so if we come in here and we put a port for example we just say port 3001 now when we run our server it's going to be running on port 3001 and we can test that by saying npm run dev start which is that command we created in our package json that runs our server as you can see here we're running a server that's on port 3001 so now what we need to do is just to create a basic git route that's going to return a list of all of our different posts so do that we first need to import the prisma client that we're going to be using so this is coming from at charisma client and we're getting the prisma client and then we can get an instance of prisma which is just a new prisma client just like that now with our app we can say app.git again just like express and inside of here we're going to have our path which is just going to be our root path actually we're going to call this slash post because we're getting all of our post we're going to have a request and a response and inside of here we can use that prisma client to actually try to access our data so i'm going to make this asynchronous because prisma is asynchronous and we can await prisma dot post dot find many and you'll notice that i'm not actually getting any auto complete for this so one thing that you can do to fix your autocomplete hit control shift p and search for typescript you'll see this typescript restart ts server if you run this it's going to restart your typescript server which is hopefully going to fix your autocomplete for prisma now you can see i'm getting my autocomplete so i can say find many and in here that's going to get all of the different things so if i pass it nothing for the where clause here it's going to get all of the different things we can pass in a select to tell it exactly what columns we want to get for example we only care about the id so i'm going to say true give me the id and i only care about the title so i'll say true the reason for that if i go back here is i only list out the title and then when i click on it it's going to use the id to bring me to that exact post over on this side of my screen i can just expand that out a little bit so it's easier to see you can see here we're just listing out title and that's it and the link from this goes to the id super straightforward so that's why we're only returning that information and instead of having to do like a response.send and all that complicated stuff with this we can just say return and it's just going to return the data for us as json so now if we try to go to that url which is localhost 3001 slash post hit enter you can see it returns to me that json data so as you can see we're at localhost 3001 slash post and i have an id for my first post which is titled post one and an id for my second post titled post two super straight forward now one thing that's really important when you're dealing with creating an api is actually handling errors right now if this throws an error we're not actually handling that at all and it's just going to give us some complicated jumbled up error mess that we can't actually process so i'm going to create a helper function for us we're going to call this commit to db which is just going to take in a promise and this helper function is going to determine if there's an error in our prisma related code it's going to make sure to handle that error and properly send it down to the user without just like vomiting on our server and doing something weird this is going to be an async function because we are going to be doing asynchronous code and inside of bastify there's a really handy function called whoops app.2 and this 2 function is actually a part of that sensible library that we installed so right now we're not using that sensible library so we need to import that so we can come up here we can say import that's going to become from fastify sensible just like that and the library itself is called sensible then to use this we can just come down here and say app dot register and we can register that sensible library so now we're using that sensible library and if i come down to here you can see we now have auto complete for that two method and all this two method does is it takes in a promise some type of asynchronous code which in our case this is asynchronous code and it's going to return to us an error and it's going to return to us as a result so if we have an error it gives us an error if we have a result it gives us a result so we're just going to await that we're going to say we have our error and our data so if we have an error i want to do something otherwise if we don't have an error i'm just going to return our data down to the user so if we have an error instead i want to return app.http errors which is something that came in that sensible library and i want to return an internal server error an internal server error is a 500 error it essentially means that there's something wrong on the server all the user information was recorrect but our server did something wrong like if our database throws an error it means there's something wrong and we're not really sure what it is and inside of here i just want to return the message for our error so what this is going to do is throw a 500 error from our server send it down to the user and it's going to give them the message for that error so it's really helpful for our user then what we can do is we can take this commit to db and we're just going to wrap our promise in this so we can just do this and now our promise is wrapped inside of that so what's happening is we call this function we're passing down this prismacode this prismacode is running inside of here if it has an error it's going to give that error down to the user otherwise it's going to take the data and return that just like normal so if we refresh over here and i just expand my page so you can see it we're still getting the same exact data being returned but if we had some type of error like let's just say we put some bad code in here and now we refresh this you're going to see hey status code 500 that's what i was talking about that's like that internal server error let me just move my camera a little bit you can see it says error is an internal server error and the message is saying asdf is not defined so it's giving us the message the status code and the error it's all really useful stuff and that's why i really like using that sensible library inside of fastify let's just bring this back to how we had it before i'm just going to change that back to true so we have all of our information working as it was before and we're getting the correct responses showing up on the right hand side of our screen now i could go ahead and start adding in more methods on our server but instead what i would like to do is to start working on the client so at least we have something to look at because right now just looking at this is really ugly and i'd like to actually have some ui to look at so we're going to go over to our client so i'm going to create a brand new terminal tab i'm just going to cd into that client folder so we're actually inside the client folder into here i want to install one single library and this library is called axios axios it just makes using the fetch api in the browser so much easier which is why we're going to install that library now inside of our client folder what we can do is we can open up this source folder and we can run our application so we can say npm start that's going to start up our application so if we just give it a quick second here we're going to wait and it's going to pop up on the right hand side of our screen so just a second here there we go so now it's loading up and right now the only thing i have in our app is just the text hello world so once this is done running it should just say the text hello world on the right hand side of our screen there we go super straightforward stuff now the thing that i want to do next is to start hooking up our application to take the data down from our server and there's a lot of different ways i could do this but what i want to do is i want to make it as reusable and flexible as possible so we can really easily expand our application i'm going to create a couple folders here i want to create a folder called services this services folder is going to be all the code that deals with calling out to our api that way all of our api calls are happening in one single folder so i can create a new file in here i can call this for example posts dot js and now all of our requests for our server that go to a post such as getting a list to post or getting an individual post are going to be in this one single file i'm also going to make another file in here this one's going to be called make request dot js and this is going to be the helper function that does all the requests for us and all of our other files are going to be really straightforward so inside of here we're going to export a function called make request this is going to take in a url as well as some options and this is just going to directly call axios for us so we can return calling axios by saying axios and we just pass it in our url and our options and then we can just have a really simple dot then and a dot catch so our dot then is just going to take in our response and it's going to return our data so we can say res.data our dot catch is going to be a little bit more complicated but not too bad we're going to have an error and it's going to take that error for now we're going to save so we can see this a little bit better formatted what i want to do is i want to return a new promise which is a rejection so we're going to reject a promise that is just going to go into our error so we can say error dot response dot data dot message and sometimes this error is not going to be populated like we expect because this is what it's going to look like from our server but if we have an error on our client it's going to be slightly different so we just want to make sure hey if we have an error property then do all this stuff otherwise if we don't just render out the text error just like this so it's either going to get a custom message or it's just going to have the text error and that's going to be what this function does so all this make request function does is it takes our normal axios request and it breaks it down into two things if it's successful it returns the data if it's an error it returns us a message it just makes it a little bit easier to use this promise since the exact result is going to be our data or our error this just cleans up that code because we otherwise would have to do this everywhere in our application also we need to import axios so we can use it so we'll say import axios from axios and one other thing i want to do is create a variable called api the reason i'm creating this variable is because every single request in our application is going to go to localhost 3001 slash something we have the same base url for every single request we make so we can use axios.create to set some default parameters for example we know that our base url is exactly the same this is going to come from our env file it's going to be called react app server url and it's really important if you're using environment variables in react they all must start with react underscore app underscore whatever the name is otherwise it won't work so now we can create a env file just like this make sure i move it into the correct folder there we go inside of here i could say react app server url and that's localhost 3001 make sure i put the http at the front and that is our url right there so now every time we make a request it's going to use this base url as long as i use api here instead of axios also i'm going to pass with credentials as true and that's because we're going to be using cookies in order to store our user information and if you don't have this set the cookies don't actually go with your request this is just going to make it when we start implementing user information this is going to make it so it sends everything correctly it's going to give the cookie to the server which is what we want so now that we have this function written we can actually use it to create our function for getting our post so we can say git posts just like that and this is going to be a function and all this is going to do is return make request and we're going to pass in slash post so it's just making a request to that post url inside of our server and the nice thing about this is that's how dead simple this function is i mean it does not get much easier than this and that's because we did all the boilerplate code right here which means we don't have to copy it anywhere else so now we can create a file and we're going to put it inside of a folder called components and it's just going to be called post list.js so here i want to export a function called post list and inside this post list function for now we can just return the text that says h1 host list and in our app we can render out this post list post list there we go now if we refresh our page over here you can see it says post list instead of hello world which means we're rendering out this component now what we can do is we can use a simple use effect just like this make sure i import this at the top of our page from react there we go and inside this use effect i want this to only run the very first time our server starts up and i want to make a request to that post so we want to get our post just like this this is going to return to us some data so we can say then set posts so we're going to have some state post set post equals use state just like that and by default i want this to be an empty array and in here json.stringify hosts so let's just give it a save real quick and see what happens you can see it starts out as an empty array and then nothing happens we probably have an error let me inspect and see if we do bring this over look at our console and you can see of course we have an error failed to load the server responded with a status 404 uncaught promise so essentially we're having a 404 error being thrown it's saying it cannot find that url let's see exactly what url it's trying to access we can go to the network tab to do that what i want to do is i just want to do a refresh on our page expand this a little bit so we can see and you can see eventually after a little bit of waiting we're getting a response and it just says cannot get slash post so there's something going on that is incorrect the thing that is incorrect is we created this env variable file right here but we never restarted our server after we created it you need to restart your react application every time you make changes in this file otherwise they won't persist so now when we restart this give it a second it's going to refresh our page and we should see that we're going to get a list of our posts being printed out and of course it looks like we're still not getting that list printed out so if we just inspect our page let's take a look at what this error is we go to our consulate saying hey access to this is not you know allowed we're having a course error we need to make sure we implement course this is luckily very easy to do because we're using that course library so if we go into our server what we want to do is we want to import that coors library we'll just call it course and it's coming from fastify slash course just like that and we can say we want to register that course library whoops register this course library and we want to give it some options as well these options are going to be the origin so what url are we making our request from this is going to come from an environment variable we're going to call this our client url and we also say that that our credentials here is true because we're sending along cookies this again just ties in with that with credentials from axios so this origin is the link to our url for our client so we can just come into our env file we can say client url we know that this is localhost whoops localhost 3000 that's what by default react runs on so now with that fixed hopefully when we make a change or when we refresh our page it should work but it looks like it's still not working let's see exactly what the error is so we can inspect our page go over to our console and we're getting the exact same error we're still having those cores errors this is again a matter of having to restart your server when your env file changes so we're going to restart this server real quick to get those new file changes implemented and now hopefully if we refresh our page it should work and it does as you can see if we expand this over we're getting essentially all the data from our server we have the ids and we have the titles for our different posts being returned onto our server so now we can actually print those out onto our screen so let's go back to that post list component and instead of returning an h1 here instead what i want to do is i want to loop through my post so we're going to say post.map for each post we want to return something and what we're returning here is just going to be a really simple object we're going to return an h1 and this h1 has a key which is our post.id just so we have a unique identifier for it and then inside of our h1 make sure we close that off we're just going to put a simple anchor tag so we're just going to come in here we're going to say anchor tag href is going to be pointing to our post url and our post url is going to be slash post slash and we want to get our post dot id that's going to link us to that post page and we can just close this off and we can put our post dot title inside of here now if i just give that a quick save refresh you can now see we have two links one going to post one and one going to post two pretty straightforward now obviously when you're working with react most often you're going to be doing react router instead of anchor tags like this so let's actually implement react router into our application instead of using these anchor tags so let's just make sure we close out here and install react router dom and i'm also going to install a library called react icons while i'm at it because we're going to need that later that react icons library just gives us these you know trash can and edit icons really easily that's all that that is going to do so with that done let's get our server restarted by calling npm start now we can swap these out for link tags inside of react router so to work with react router if you're unfamiliar with it i have a full crash course i'll link in the cards in the description for you that covers it but for this application it's going to be very very straightforward instead of our index here we need to get our browser router so we're going to import from react router dom we're going to import that browser router and we're going to wrap our application in that so we're going to say that our application goes inside this browser router then inside of our app we're going to return our routes for our application we only really are going to have two routes so we're going to say here we're going to get our routes which comes from that react router library and we're going to have two different routes the first route we're going to have is our home route which is just i slash and this element that we're going to be rendering for that is going to be our post list just like that we're also going to have another route this one is going to be at slash post id just like this and this is going to render out a post component we don't have that yet so for now i'm just going to render out null so it's going to render out nothing so this is all that our routes are i need to make sure i import that route component there there we go so now we have a route that leads to essentially this and a lot that leads to nothing i could even just come in here and say h1 post so now if i change to do in our post list these anchor tags to links from react router which we can do quite easily and i change this a fret href to a 2 here now when i click on these links it's going to bring me to that page and you can see for now it's just printing out the text post which is what i put right here you know no matter what this is that's what it's going to be printing out and now we can just go back though to this page right here also one thing i want to do is i want to wrap everything in our application inside of this container so we're going to give this a class of container drop this down like this that's just going to give us some nice spacing so it's not all cramped on the edge of our screen so now at this point in our application we have the most basic communication between our server our database and our client i do want to clean up our code a little bit though because if we look inside of our post list here first of all it's kind of cumbersome to always have to write out our use effect like this secondly we're not taking into account loading states or error states so i'd like to fix all of that by just creating a simple custom hook that's going to create all this logic for us we're going to create a new folder this folder is just going to be called hooks and inside of here i'm going to create a use async.js custom hook and this is just going to take any code that runs asynchronously for example this git post and it's going to return to us the data a loading state as well as an error if there is an error really straightforward i'm actually going to implement it in two different ways the first way i'm going to implement it is where it's going to automatically run in a use effect for you anytime anything changes which is good for instances like this post list but i'm also going to create a second instance that allows you just to run it whenever you want so for example if you create a comment in this page like you type in here a comma and you click post that is going to run an asynchronous request and we want to be able to fire that off whenever we want so i'm going to have two versions one that's automatic and one that allows you to fire it off on your own time so inside use async let's export both of those functions the first function is going to be called use async this is going to take in a function and it's going to take in some dependencies just like that which by default is an empty array and then i'm going to copy this i'm going to paste it down and we're going to create a use async fn version and this fn version has the exact same dependencies but it's just going to return to us a function instead of automatically running the code for us now to make both of these different functions work we're going to need a third function and this is going to be called use async internal and this function doesn't get used anywhere else but instead inside of this file and this takes in a function it takes in some dependencies and we're also going to take in an initial loading variable which we're going to set to false this initial loading variable right here all that this does is determine if our loading state starts out as true or starts out as false really pretty straightforward so we can create our different state we're going to have a loading state and it's going to be equal to use state whoops use state and by default it's going to be set to our initial loading value so it's either going to be false or true depending on which one of these function versions we use then i'm going to copy this down a couple times because instead of loading we're going to have our error and our error by default is going to be nothing so we can clear that out and then here we're going to have our value just like that so we have our loading our error and our value that we're currently taking care of now we're going to have a function called execute and this function is going to be using use callback and it's going to take in some random parameters just like this so in order to understand exactly what's going on inside of here what we're doing is we're creating our different state that we care about like we want to know is this loading is there an error what is the value of our result and this callback right here that's getting this function called execute this is just the function that we call in order to set all these different values so this execute is going to call whatever function we pass in to use async so if we go to our post list the way we would use this here is something like this we would have this say const and we would get our data so for example we'd say like loading error value and we would just say equals use a sync just like this and we would pass it in that get posts function and our dependencies which is just an empty array so we can just leave that off if we want to because by default we set it to an empty array now we've cleaned up all of our code we have our loading our error and our value we can even set this to post for example just like that oops flop that around there we go so now we have our three different properties that we care about and this is just going to automatically run this code for us inside this use async so this execute right here that i'm talking about is the thing that's going to be automatically run for us so let's write our execute code first when we call the execute function we want to set our loading to true because we are currently starting to run this application then i want to return the results of our function so our function is going to take in all the different parameters so the way that this execute function is going to work is it's going to work exactly the same as our normal function we're just adding in additional functionality to set all these different values for us automatically so this func right here would be like our git post that function right here git post we're calling gitpost with all the parameters we care about in our case there are no parameters we're just calling as is and then what we're going to do is we're going to say hey you know what when we get our result back we're going to be getting our data so what we can do is we can say set value to our data we can set our error to undefined because we no longer have any error if we got to this point and we can return our data so if we want to chain onto the end of this we can do so with our data we can also get a dot catch inside of here which is going to be almost identical so i'm just going to copy this code down here and instead of setting our value we're going to set our error so we're going to say our value is set to undefined and our error is set to error also i want to make sure here i do a promise.reject and i want to reject that error just so we again are making sure if there's an error we rethrow that error to be used at a later time finally we're going to add in a finale and all this is going to do is say set loading to false because now we are no longer loading our data because we have finished the loading process and we set our value or our error lastly since this is a used callback and we have some dependencies that we care about what i want to do is i just want to say you know what we get our dependencies i want to make sure that we only ever refresh our execute function every time our dependencies change obviously in this example we don't have any dependencies because we just want to get all the posts and then that's it but if we had like an id for example for a post we would want to refresh our post every time that id changed so that's what we have and now we just need to return our pertinent values so we're going to return loading error value and execute so we're returning those three values we care about as well as the ability to execute this function so if we come up into here our use async func is going to be really straightforward because all we're going to do is return the results of calling use async internal we're going to pass it our function and our dependencies and it's going to be false for our initial loading because by default this is the function version that we can call whenever we want so it's obviously not going to run immediately so loading is going to be false this version up here is going to be slightly different though here we want to get out that execute function as well as all the other state that is inside of our function that's the things like loading error value and so on it's going to be coming from that use async internal pass it in our func our dependencies and here we want to set our initial loading state to true because we're going to be using a use effect to immediately invoke this function so we're going to be running that execute function immediately which is really the key right here we're immediately executing this function and here we're just going to put in our execute function as our dependency so every time our dependencies change our execute function is going to get updated and this use effect every time our execute function gets updated reruns itself and by default we're setting loading to true because immediately we're running this function then all we need to do is return all of our different state information and this use async is exactly the same as use async function except for we no longer have the execute function we took that out and we're immediately invoking it automatically and re-invoking it every time our dependencies change so with all of these changes we go back to our application and we just do a quick refresh it looks like i spelled funk wrong somewhere it looks like right here there we go let's try saving now you can see that we no longer have those errors but we're probably getting an issue somewhere else just back to our page here come over to our console cannot read properties of undefined reading map and the reason for that if we go back to our post list is we are currently in the loading state because by default post starts out as nothing so we need to just have a check in here to see if we're loading we also need to check to see if we're in an error state so if we're loading let's just return a simple h1 that says loading just like that and if we have an error let's just return a simple h1 give it a class name of error message that's just going to give us some red text and we'll print out our error message inside of there so now when we're loading it's going to say the text loading so if i refresh this we should see a very quick blip of it saying loading and i can actually slow down my network speed come over here i can change my speed to slow 3g just like this so now if i do a refresh you can see it's going to be much slower but as soon as the page loads it's going to say the text loading on the screen and that text for loading is going to stay there for a while before eventually the actual data shows up now this is obviously very very slow to load because i'm on a very slow 3d connection but you saw that that text loading popped up for a while before the actual data showed up now i'm going to just get rid of all that throttling and
Original Description
FREE React Hooks Course: https://courses.webdevsimplified.com/react-hooks-simplified
If you are wanting to build a complex full stack project then this is the video for you. In this video we will be covering how to setup and connect a backend, database, and React frontend. This is a large and complex project, but is amazing for your resume.
📚 Materials/References:
FREE React Hooks Course: https://courses.webdevsimplified.com/react-hooks-simplified
GitHub Code: https://github.com/WebDevSimplified/nested-comments
Prisma Video: https://youtu.be/RebA5J-rlwg
Cors Video: https://youtu.be/PNtFSVU-YTI
Cors Article: https://blog.webdevsimplified.com/2021-05/cors
React Router Video: https://youtu.be/Ul3y1LXxzdU
React Router Article: https://blog.webdevsimplified.com/2022-07/react-router
React Context Video: https://youtu.be/5LrDIWkK_Bc
React Context Article: https://blog.webdevsimplified.com/2020-06/use-context
Regular Expression Video: https://youtu.be/rhzKDrUiJVk
🌎 Find Me Here:
My Blog: https://blog.webdevsimplified.com
My Courses: https://courses.webdevsimplified.com
Patreon: https://www.patreon.com/WebDevSimplified
Twitter: https://twitter.com/DevSimplified
Discord: https://discord.gg/7StTjnR
GitHub: https://github.com/WebDevSimplified
CodePen: https://codepen.io/WebDevSimplified
⏱️ Timestamps:
00:00:00 - Introduction
00:01:55 - Prisma database setup
00:13:26 - Server setup
00:21:01 - Connecting the client to the server
00:30:57 - React Router setup
00:33:19 - useAsync custom hook
00:41:58 - Get post server route
00:44:23 - Post context setup
00:50:44 - Render comments
01:09:30 - Comment form component
01:15:45 - Create comment client logic
01:19:15 - Create comment server logic
01:21:21 - User authentication
01:26:00 - Saving comments on the client
01:30:15 - Comment reply logic
01:34:35 - Update comment server logic
01:38:00 - Update comment client logic
01:42:53 - Delete comment server logic
01:43:54 - Delete comment client logic
01:46:23 - User permission
Watch on YouTube ↗
(saves to browser)
Sign in to unlock AI tutor explanation · ⚡30
Playlist
Uploads from Web Dev Simplified · Web Dev Simplified · 0 of 60
← Previous
Next →
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
Introduction to Web Development || Setup || Part 1
Web Dev Simplified
Introduction to Web Development || Understanding the Web || Part 2
Web Dev Simplified
Introduction to HTML || Your First Web Page || Part 1
Web Dev Simplified
Introduction to HTML || Basic HTML Elements || Part 2
Web Dev Simplified
Introduction to HTML || Advanced HTML Elements || Part 3
Web Dev Simplified
Introduction to HTML || Links and Inputs || Part 4
Web Dev Simplified
Learn Git in 20 Minutes
Web Dev Simplified
5 Must Know Sites For Web Developers
Web Dev Simplified
10 Best Visual Studio Code Extensions
Web Dev Simplified
Learn CSS in 20 Minutes
Web Dev Simplified
How to Style a Modern Website (Part One)
Web Dev Simplified
How to Style a Modern Website (Part Two)
Web Dev Simplified
3D Flip Button Tutorial
Web Dev Simplified
How to Style a Modern Website (Part Three)
Web Dev Simplified
Animated Loading Spinner Tutorial
Web Dev Simplified
How to Write the Perfect Developer Resume
Web Dev Simplified
Animated Text Reveal Tutorial
Web Dev Simplified
Learn Flexbox in 15 Minutes
Web Dev Simplified
Custom Checkbox Tutorial
Web Dev Simplified
Start Contributing to Open Source (Hacktoberfest)
Web Dev Simplified
JavaScript Shopping Cart Tutorial for Beginners
Web Dev Simplified
Responsive Video Background Tutorial
Web Dev Simplified
1,000 Subscriber Giveaway
Web Dev Simplified
How To Prevent The Most Common Cross Site Scripting Attack
Web Dev Simplified
Transparent Login Form Tutorial
Web Dev Simplified
The Forgotten CSS Position
Web Dev Simplified
How to Code a Card Matching Game
Web Dev Simplified
10 Must Install Visual Studio Code Extensions
Web Dev Simplified
Learn CSS Grid in 20 Minutes
Web Dev Simplified
Learn JSON in 10 Minutes
Web Dev Simplified
10 Essential Keyboard Shortcuts For Programmers
Web Dev Simplified
What Is The Fastest Way To Load JavaScript
Web Dev Simplified
Differences Between Var, Let, and Const
Web Dev Simplified
How To Install MySQL (Server and Workbench)
Web Dev Simplified
Learn SQL In 60 Minutes
Web Dev Simplified
How To Solve SQL Problems
Web Dev Simplified
What Are Design Patterns?
Web Dev Simplified
Null Object Pattern - Design Patterns
Web Dev Simplified
Your First Node.js Web Server
Web Dev Simplified
How To Setup Payments With Node.js And Stripe
Web Dev Simplified
How To Learn Any New Programming Skill Fast
Web Dev Simplified
Asynchronous Vs Synchronous Programming
Web Dev Simplified
JavaScript ES6 Arrow Functions Tutorial
Web Dev Simplified
Are You Too Old To Learn Programming?
Web Dev Simplified
JavaScript Cookies vs Local Storage vs Session Storage
Web Dev Simplified
JavaScript Promises In 10 Minutes
Web Dev Simplified
Builder Pattern - Design Patterns
Web Dev Simplified
JavaScript == VS ===
Web Dev Simplified
JavaScript ES6 Modules
Web Dev Simplified
8 Must Know JavaScript Array Methods
Web Dev Simplified
CSS Variables Tutorial
Web Dev Simplified
JavaScript Async Await
Web Dev Simplified
How To Choose Your First Programming Language
Web Dev Simplified
Easiest Way To Work With Web Fonts
Web Dev Simplified
Singleton Pattern - Design Patterns
Web Dev Simplified
Responsive Navbar Tutorial
Web Dev Simplified
CSS Progress Bar Tutorial
Web Dev Simplified
Learn GraphQL In 40 Minutes
Web Dev Simplified
What is an API?
Web Dev Simplified
Learn How To Build A Website In 1 Hour!
Web Dev Simplified
More on: LLM Engineering
View skill →Related AI Lessons
⚡
⚡
⚡
⚡
Applying Scalability in Backend (CodeBuddy)
Medium · LLM
Why Every Backend Developer Should Learn Nginx Before Going to Production
Medium · DevOps
Connecting Frontend to Backend: A Backend Engineer’s Reality Check
Medium · Programming
Build Secure Authentication System Using Access and Refresh Tokens
Medium · Python
Chapters (20)
Introduction
1:55
Prisma database setup
13:26
Server setup
21:01
Connecting the client to the server
30:57
React Router setup
33:19
useAsync custom hook
41:58
Get post server route
44:23
Post context setup
50:44
Render comments
1:09:30
Comment form component
1:15:45
Create comment client logic
1:19:15
Create comment server logic
1:21:21
User authentication
1:26:00
Saving comments on the client
1:30:15
Comment reply logic
1:34:35
Update comment server logic
1:38:00
Update comment client logic
1:42:53
Delete comment server logic
1:43:54
Delete comment client logic
1:46:23
User permission
🎓
Tutor Explanation
DeepCamp AI