Learn React With This One Project
Key Takeaways
Learn React by building a project, covering React fundamentals, components, and state management, with a focus on practical application and hands-on learning.
Full Transcript
If you've been wanting to learn React, this is the perfect video for you. I'm going to show you how to build out this fully functional habit tracking application that does everything you would expect from a normal habit tracker, but I'm not just going to be showing you the lines of code to write. I'm also going to be explaining what every line of code does and going in-depth into every single major concept of React. So, that way by the end of this video, you not only have this full project built out, but you also have a strong understanding of React, so you can build any of your own projects as well. Also, if this way of learning sounds appealing to you, my full React Simple course is currently on sale for this week, so I highly recommend checking it out. It's over 40 hours of literally every single thing you ever need to know about React, and at the end of the project, we build out a fully functional job board that includes authentication, payments, and so much more. This is the ultimate React course if you really want to land a job as a React developer. So, if you enjoyed this video, I highly recommend checking this course out. It'll be linked in the description, and it's currently on sale for this week. >> [music] >> Welcome back to Web Dev Simplified. My name's Kyle, and my job is to simplify the web for you. And the very first thing we need to do to create a project with React is to type inside the terminal npm create vite@latest. And then, what I like to do is I just like to put a period after this command, and that'll create my project in the current folder I'm in. But, if you wanted to create it in a specific folder, just type in the name of that folder. In our case, I want it to be in the current folder I'm in. What this command does is it essentially spins up Vite, which is a bundler that essentially allows you to write all of your React code, and then it converts it to something that the browser can properly handle. Now, in our case, we want to scroll down to the correct framework, which is going to be React. We can select that by just hitting enter, and then you can see we can select a bunch of different varieties, and your list may be slightly different than mine depending on when you watch this video. But, in our case, we want to use TypeScript specifically with the React compiler. Now, the compiler is not really something you have to worry too much about, but it's just something in there to help optimize your code in React, so that's why we're choosing the compiler version. Now, when we do that, we can just say we want to install it with npm and start it immediately, and it's going to go through install all the different dependencies that we need and then start up our application and it'll show us on the right-hand side of our screen that application when it's actually done being pulled up. And if we take a look at the starting code for this application, it's relatively basic. Now, that looks like there's a lot of code, but you can pretty much ignore everything that's not inside this source folder cuz the source folder is where all of your actual React-related code is going to go and everything outside of here is just setting up things like your linter with ESLint and setting up your bundler with this vite.config file. Now that's done, you can see that right here we have this URL we can open up and it's just going to give us the starting application for our page. Again, yours may look slightly different depending on when you're watching the video, but it doesn't actually matter what this looks like cuz we're going to be deleting everything inside this starting application. Now real quickly going through the actual starting code, I'm just going to open up this source folder. We have this assets folder which just has a some of the images that are being used on the page. We can remove this cuz we're deleting all the starting code. We see that we have this CSS file here. Again, that's all just for the default rendering so we can delete that since we don't need it. We have this other CSS file here. Again, we're not going to be using this so we can completely delete this file as well. And then finally, we have this main.tsx and app.tsx. And this is where all of our React-related code goes. So, anything in React is going to be a JSX file and since we're using TypeScript, we're using a .tsx extension. And that allows us to write this like angle bracket style code that looks a lot like HTML directly inside of our JavaScript. That's what JSX is and that's essentially what entirely of React is built on top of is this JSX syntax. And again, since we're using TypeScript, we use the .tsx extension. Now to finish up getting our page to work like we want, since we removed that CSS and those assets files, we can just delete everything inside this file. And instead, we're going to just say export default function and we're going to call this function app. And by default, we're just going to return null from here so it should just give us a completely blank page with that file being saved. And then inside of here, that index.css file, we removed that as well so we're going to delete that from this file. And now, we just have a completely blank page. And if we wanted to, we could write something in that page. So, for example, in this app.tsx, again, since we can pretty much write anything we want that's normal HTML, I can just put some random text in an H1, and you can see that automatically shows up on my page. And everything is automatic. When you save, it automatically refreshes and puts all your content on the right-hand side, wherever your browser is. So, you get automatic refresh, which is really nice. And again, since we have this JavaScript syntax that's JSX, we can write our HTML code essentially directly inside of our JavaScript with very small changes that I'll cover as we get to those particular points. Now, for our particular project, I'm going to be using Tailwind for all of our styling. It's okay if you don't know Tailwind, it's not important that you do. It's just going to be what we use for our CSS styling. So, if you go to the Tailwind site, there's a section on using it with Vite. We just want to copy over the command for installing Tailwind. So, we're going to paste that down to install Tailwind. And then, we need to configure Tailwind inside of this Vite config file. That's the file I told you right here that sets up all of our bundling. You can see we have React as well as the React compiler because that's the presets we chose. But, we just need to add in Tailwind CSS. So, let's copy over the import for Tailwind CSS. And then, let's make sure we use Tailwind CSS inside this plugins array, just like this. And now, if we give that a quick save, we now have Tailwind installed into our application. The only thing we need to do is to make sure in some CSS file that we import this Tailwind CSS. So, let's create a brand new file. We'll call this index.css. And I just want to import that Tailwind at the very top. And then, in my application, this is something that's kind of interesting about React and a lot of other bundlers. The way that Vite works is if you just import a CSS file right here, so we can import that CSS file that we just created, it'll actually find that CSS file, compile it, and put it into your page properly with a link tag and everything else. So, you don't have to manually do that yourself. So, now we have that CSS file in our page. And if we look over here, and we just refresh our application by restarting it, by just running npm run dev, that'll start up our application on that exact same port. And now, if we refresh, you'll notice our font size has been drastically decreased. And that's again because we are using Tailwind CSS, which automatically gives us the ability to style things using those classes. So, inside of JSX, instead of writing class and then putting the class, you actually need to write class name. That's just because class is a keyword in JavaScript, so you can't use it directly. So, if we write class name followed by any class names we want. So, in our case, we could change the color of this, which is just text, to like red 500. And now you can see that our text has changed to a red color. So, we just have Tailwind properly hooked up with our application. Everything automatically refreshes. And again, since we're using React, we need to make sure we write class name instead of class. And that's all we need to do to get started with setting up Tailwind and our application. So, now we can finally move on to actually creating the different parts of our application. And the first thing I want to focus on is what you need to think about when you're a React developer. Let's take a look at the actual current working version. Let's zoom this back out to more reasonable zoom level. And you can see that we have a few different sections of our application. We have this nice header section, which has a title. It tells us how many different things are done. It also has the ability to navigate through our dates. So, you can see as we navigate our dates, the rest of our application changes. We have this next section, which is like this form, where we can type in some name for a new habit. We can click add, and that new had habit is being added to the page. And then we also have the ability to delete things inside this list by clicking this delete button. So, that's kind of the main functionality. Also, the next section of our application is this list. So, you can see it lists out each one of our habits inside this list. And each habit itself is kind of its own element of the page cuz you can see it shares the exact same pattern between every single habit inside of our list. So, we can essentially think of this as three different sections of our application. We have the header, which contains all of our date information and the title. We have a form for adding new habits. And then we have a list of each one of our habits. And when you're working in React, you want to break your page down into these different sections. And they are generally called components because React is a component-based library, and every single thing we build is going to be a component. So, we want to have a component for this top section, a component for the form in the middle, and then a component for the list of each one of our different habits. And we're going to put all of that directly inside this app page right here. Now, this app page is essentially the starting point for your application. Technically, this main file is the starting point, but almost always the main file will import your app and nothing else. So, the app file is kind of your main starting point for your entire application. And inside of here is where I want to create that layout. So, we're going to have a div that wraps our entire thing. Let's make sure that's on a line like this. And we know that we have a header section, we have a form section, and then we have a list of each one of our habits. So, what we're going to do is we're actually going to create our own custom components for each one of those. And the way custom components work is they're just a function. So, in React, you just type a function, and then you want to give the function a capital letter name. So, it's going to have a capital letter as the first part of the name, and that is different than normal JavaScript functions, and it's actually required for it to work properly with React. So, we have a header, for example. So, we can call this header just like that. And now, inside the header, we can return whatever content we want, and we can render that out. So, let's just put an H1 that says header directly inside of here. And now, I can use that component inside of this section by using the exact same ankle brackets I would with HTML, but by putting my custom component name just like that. So, now I've created a header component, and it's going to render out whatever I put inside of here. So, if I look at my application, you can see here it's rendering out that text header because that's what's in my component. And if I change this, you can see it renders out header, too. So, essentially, it just takes the code in here and pastes it directly wherever I put that component inside my application. Now, we obviously want to do much more inside of our header. So, let's go ahead and actually see what our header is going to look like and start working on the code for this header section. So, the first thing with my header is it's essentially broken into two sections. I have this left-hand side and this right-hand side. Easiest way for me to lay that out is with flexbox. So, we'll come in here, and we're going to use a div. And actually, I'm going to use a header because it's more semantic HTML, which is obviously better. There we go. And inside of here, I'm going to have two sections. The first one is going to be a div on the left, and the second one is going to be a div on the right-hand side. So, one is going to take care of this, and one is going to take care of this. And to make sure I separate those elements out, we're going to come in here and we're going to use flexbox to separate them. So, we're going to say flex. We're going to put the items in the center and we're going to justify content between and that's just going to make sure that it center aligns these elements and pushes them as far away as possible from each other. Now, the next section is going to be my left-hand side, which again, I want to use flexbox, but I'm going to do flex of a column. So, it's a vertical flexbox. And then I'll come in here with a gap of one just to space these elements out a little bit from one another. Now, inside of here is where I want to put my habit tracker text as well as this one out of one content done. So, I can come in here with an H1. This H1 is going to say habit tracker just like that. And then below that, I'm essentially going to have some text inside of a span that's going to say like one out of one done today. That's these two elements of our page. Now, let's go ahead and actually style what they should look like because right now, if we save this and we look, you can see we have our text, but it has no styles, which is obviously not ideal. So, for our H1, let's come in here with the class name. We're going to use the text 3XL to increase the size of it and then we're going to come in here with a font of bold to make that a bold font. So, now you can see it's a much larger bold font. And for our one out of one, we can come in here with a text zinc of 400 and a text of small to make it slightly smaller and more gray. And now you can see that that looks exactly like we want it to as well. Now, we should probably work on the background color and everything else for our application. This can actually be done in our CSS file cuz we want to select the entire body element. So, I want to specify my background color and we can just use the variable which is color zinc 900. That comes from Tailwind CSS. And then for our color of our text, we want to change that to a white color. So, we'll just say color zinc 100 and that's going to give us a white color by default. And there you go, you can now see we have that background set up and everything overall is looking quite good. What we want to do though is add a little bit of spacing from our elements up here. So, in our main app, which is the thing that wraps our header, let's come in here and add a maximum width of 2XL so it's never too large on our screen. We're going to add some margin on the right and left of auto. That makes sure it centers itself on large screen sizes. And then we're going to add a little bit of padding on top and bottom. And then we're going to stack everything in a vertical direction with a gap between them. So, there we go. That nice and centered our text in the screen by giving a little bit of padding. And if we had a very large screen size, you can see it doesn't ever expand past a certain width, which is exactly what we want. So, let's shrink that back down. And let's go ahead and finish out what our actual header's going to look like. So, inside of our header, the next section that we can work on is going to be the right-hand side. So, let's look at what that looks like. You can see we have this text for the dates as well as two different buttons. So, what we can come in here is add those little flex box classes. So, we'll copy over the exact same flex box to this section over here. So, now you can see we have that vertical stack going on. And inside this vertical stack, we're going to have some text in a span. That's just going to be our dates. So, we can say like April 6th through April 12th, just like that. And again, the text on this is going to be pretty much identical to that one out of one done. Exact same font and exact same font size. So, if we give that a save, look over here, you can see that's already showing up and it's centered, which is what we want. Next, we need to add some buttons. And these buttons need to be stacked horizontally, so we're going to wrap them in their own div. Make sure that they are centered. And with a gap of three, just like that. And now we can put in each one of our different buttons. So, we're going to have a previous button. And we're going to have a next button. And if we go ahead, you can see we have our previous and next button. And since we're using Tailwind, they have no styles by default. Now, we could manually style what these buttons look like in line right here. But if we look at our application, you notice we have a lot of buttons, and they all share almost the exact same style. They have the same kind of shape, the same color, the same font size. Everything is very similar about them. And in React, whenever you have something that is similar across your entire application, it is almost always better to extract that out into a custom component and then reuse that everywhere in your application. So, instead of manually writing out our button code for every button and copy and pasting it, we're going to create one single button component that encompasses all the buttons in our application. So, what we can do inside of a file here is we can create a brand new file called button.tsx. And I might as well just put that in a folder called components. This is where all of our different components are going to live. And then we can just say we want to export a function. We're going to call this button, just like that. And now we can render out our button code inside this section. So, let's just copy what we have inside of here. I want to return this as is. And now I can replace this with that button component that is custom, just like that. And now it's going to render out my button. You can see it's exactly the same as before. I can do that for both of these sections. And now you can see both my buttons are rendering out. Now, I do have a little bit of an issue. You can see they're saying previous and previous. That's cuz I currently have the text previous hard-coded into my button. Now, I could change this to next, but again it's hard-coded as next. I want to be able to pass this along into my component. This is where the idea of props come in. Props are something that you can pass from one component to another component. It's essentially like passing data to a function. So, in order to pass along props, we go back to the thing we want to pass the prop to. In our case, we could pass along what the text for this is going to be. We can just say text, and then you give it any value you want. In our case, let's give it the value of previous. And for this other button, we're going to pass in text and give it the value of next. So, now we have these pieces of data that we can use as essentially properties to our function. Right now, we're getting errors because there are currently no props being accepted. You can see this function takes no arguments. The way that props work in React is they always pass along an object. And this object is generally just going to be called props or something along the lines. And then we can give that a type. We'll call this our button props. So, let's create that type button props. And essentially, this is always an object, like I said. So, we want to define this as an object and then put each one of our properties inside of here. So, we have a text property, which is a string, just like that. And now you can see in props, we have that text property. So I can come in here, props.text, and get access to that text. And you can see here, all my errors have been removed. And if I just go and I replace the text with this props.text, it'll put the text in place. Now, obviously, if I just paste my text like this, it actually renders out props.text. It doesn't render the actual text element. In order to render actual JavaScript code in your React components, you need to wrap them inside of curly braces. By wrapping inside of curly braces, essentially, you're telling React, "Run the code inside of here as if it was JavaScript, and then whatever it returns, put inside of the actual HTML output." So now you can see by accessing props.text, I get my previous "Am I Next Button" showing up on my element, which is exactly what I want. Now, generally, when you're working with props, I like to destructure my props inline. So here, I will just write text like that, and then I can use my text directly down here. This makes it a little bit easier to work with my props, because now I don't have to put props.whatever. I can just write the actual name of the thing to make it a little bit simpler and easier to work with. Now, there's technically a way that we can improve this slightly as well. Cuz right now, you can see we're passing the text along like this, which is kind of weird. I would almost rather just be able to pass my text in between my elements, like I would do with a normal button. So I'm going to show you how you can do that as well, because it's actually very simple. Inside of React, there is a special property that's called children. And it's always available on every single custom component you create. And essentially, children is just equal to whatever you pass in between your elements. So it's whatever text you pass down to your element. So instead of calling this text, I can actually call this children, just like that. And here, I can paste in children as well. And you can see immediately, if I save, that fixes my problem over here. It's now passing on that children. And this is, like I said, a component or a function inside your props that is always there, and it's always available inside of React. Now, to type this inside of TypeScript, it's called a ReactNode. So we can come in here with children, and we can set the type to ReactNode. That is the type of whatever is being passed along. Essentially, it can be a lot of different things, but it's mostly in our case going to be just a string of text. So, it allows us to take whatever we pass between our element, and it takes it in as a special children prop that's automatically handled by react for us. So, you can pass along your own custom properties with your own name, or you can use the built-in property children to pass along specific text, for example. Now, if you wanted to pass along other things, obviously, I could just come in here, paste in whatever I want, and I can pass that along. And you don't just have to pass along strings. If you wanted to pass along a value, just wrap it inside of curly braces, and now I could pass along, for example, the number zero, and that passes along a zero number instead of the string of zero. In our case, we don't really need anything else, so we're going to leave this exactly as is, and now we can actually style what our buttons are going to look like. So, here we want to specify a class name for all of our different classes, and in our case, we're going to have a background of violet. That's going to give us that purpley color. We'll use violet 600. And then we're going to have a hover, which is a background of violet. And this one's going to be violet 500. There we go. So, now if I hover over those, it just becomes a slightly lighter color. And actually, I spelled hover wrong. There we go. So, now when I hover over them, it becomes that slightly lighter color. Now, let's go ahead and fix all the rest of our content. For example, we want to add some animation, so we'll do a transition on our colors to give us a little bit of animation. We'll make the button rounded. We'll add a little bit of padding on the top, bottom, left, and right. And then finally, if the button is disabled, we'll set the opacity to 30, so that it's a slightly more opaque color. And if it's disabled, we'll set the cursor specifically to the not allowed cursor. So, let's find that inside of here. There we go. Give that a quick save, and now you can see our buttons look exactly the same between these two examples. And when I hover over it, you can see that I get that nice hover effect. And if these buttons were disabled, for example, I just pass along disabled here, you can see that I get this nice grayed out color. So, it's working exactly like I expected to. Now, there's one other small thing I want to change about my header, and that is that this right-hand section, I want all the items to be aligned on on end. So, we'll just put items end here to move that date over. And now, we have an exact match between these two different pages, which is exactly what I want. Now, the next thing that we can work on is this form section right here. So, let's scroll up. We have our header. Now, let's go ahead and deal with our habit form, which is going to be another custom component we create. And you'll notice something, like I have these header components with no content being passed into them. Inside of React, if you ever have an empty element where you're not passing anything to it, you can actually do a self-closing element where you just put the slash at the end like this. That's exactly the same thing as what we have down here. So, you can make it self-closing like this just to make your code a little bit more concise. And again, if we add that new function for the habit form, just like that, and we make sure that it returns something, now you can see all of our errors are cleared up, and our code still works exactly the same as before. So, this is a nice little hack for writing more condensed, slightly easier to work with code. Now, another thing that's important is often times when you're creating components, especially more complex components, it makes sense to take them and move them into their own file. So, I'm actually going to create a brand new file here for my header. And I'm going to take all the code, again, remember it ends in .tsx. I'm going to take all the code for our header here. I'm going to move it into that brand new file that I just created. And what I want to do is I want to export this component so I can use it in other places. I just make sure I import my button component as well. So, now I have all the exact same code. I can just make sure I import my component here, and everything will work exactly the same as before. You can see there's no changes on this right-hand side. Now, I also want to do the exact same thing with our form. So, let's create a new file called habit form. And let's come into our app, copy over all that habit form stuff, paste it into here, export it, and then make sure in here we import that component as well. And now, we can actually work on creating what our form is going to look like. And luckily, it's a relatively straightforward form with just a single button inside of it and a single input element. So, let's create a form element just like this. And inside of our form element, we're going to have an input. That input is going to be for our single text input. Again, we can use it as self-closing. And then we're going to have a button as well, which has add habit, just like that. And again, the reason we create these nice custom components is now, just by adding that one custom component, if we look at our page, it automatically has all the styles for that add habit button, which is really, really nice and easy to work with. Now, for our input element, we actually need to add quite a few class names. For example, we want it to grow to fill the full width, so we'll add a flex one on here. And on our form, we'll add a class name of flex with a gap of two. That makes this our input fills the full width. And now, to make it so we can see our input, let's add some rounded large on it. We want a background of zinc 800. We want some padding of four on the left and right, and two on the top and bottom. We're going to remove the outline, cuz we're going to add our own outline, so we can say focus visible. We're going to add a ring two, that's going to be our own custom outline. And for the focus visible, we're also going to make sure that that ring has that violet color. So, we're going to say violet 500, just like that. And now, if we give that a quick save, you can see we have our input, and when we click on it, we get that nice little purple outline around it, which is exactly the same as the content we have over here. We can also add our placeholder text. So, inside the input, let's add that placeholder text, and we can just say new habit. Just like that. Now, if I give that a save, we look over here, you can see I get that placeholder text as well. Now, if we compare and contrast these, there is a small difference in our button. Our button is slightly different between the two. We will actually come back and fix that problem in a little bit, because it involves a slightly more advanced trick in React. But for now, I want to move on to styling this bottom section here for the actual list of items and habits that we want to work on. So, if we go back to our app.tsx, we essentially need to have a habit list, which is going to be the section that lists out each one of our individual habits. And again, let's create a brand new component for that. I'll just copy our form over, rename this habit list, and call this habit list, and we'll just get rid of the content inside of here, so it just returns null. There we go. And now if we come into our app, we can import that habit list component, and now we essentially have that, and we can put whatever text and content we want inside of here to make it render down below. So in our particular case, we want to have essentially an empty state and a state for if we have elements. So let's just create a placeholder variable called habits. We'll set it to an empty array, so we can start out by seeing what happens if we don't have any habits. So I can just have a simple if check here. I can say if our habits.length is equal to zero, well then we want to return something else. Let's say just return an h1 that says empty. Otherwise, we'll return an h1 that says full. Just like that. So now you can see it's printing out the text empty onto our screen cuz there is nothing in our list. But if we add something to our list, you can now see the text full is being printed out. So we're able to conditionally return different HTML based on certain things in our page, which is really, really important. So here we have that empty array, and I want to return essentially something saying, "Hey, you don't have any content." So let's create a paragraph tag that just says no habits yet. Add one above to get started. There we go. And let's add some styles to this as well, so we can center the text. We can give it that zinc color we've been giving everything else. And we'll add quite a bit of padding on the top and bottom, just like that. So now you can see no habits yet. Add one above to get started. So it just gives us a nice little placeholder text. Now obviously, we want to do something if we have habits. So let's pretend that we have a habit in our array and figure out what we want to do down here instead. Well, I'm going to have essentially a flex box-based list, so I'm going to put that in a class name with a flex of column and a gap of three. That's just going to space out our elements. And then what I want to do is I want to loop through every element inside my array and print it out. So if I have, for example, a bunch of different elements inside my array, I want to render every single one of them. Well, in order to do this in React is a little bit confusing because you can't just put a for loop right here and add like a return in the middle of it cuz that wouldn't work. So instead, what you need to do is you need to take whatever array you have and you need to convert it into JSX that gets rendered out into your page. And the way that that works inside of React is you just type in whatever your array is and you want to map over it and you want to convert it to JSX output. So, essentially, you're converting it to HTML and then it renders that full list of HTML in your page. So, we can loop through each one of our habits. And then we can run whatever code we want to return from here. Now, you could come like this and type in that you want to return and we could say we want to return an H1 that puts whatever our habit text is inside of it. And now you can see for each element inside of our array, it's rendering out the text for that element. If I remove an element, you can see it now only renders two elements. Again, if I have one element, it renders it and if I have no element, we are rendering this fallback value right here. So, we at least are able to conditionally render stuff if we want to just like this. And generally, when you have this situation where you're just immediately returning JSX, what I like to do is instead of putting this like bracket right here, this curly bracket and return, I replace this with a parenthesis and a parenthesis on the other end. And essentially, what that tells React is to automatically return the content in here. It's just a JavaScript feature. It just automatically returns what's in the parenthesis. So, you can essentially save a little bit of code by writing like this and it's most commonly what you'll see inside of React is code just like this. Now, our habits are going to be a little bit more complicated than just a string. So, let's actually just get a little bit of a placeholder. For example, we're going to have an ID. Let's just say like an ID of one and we're going to have a name of hi and let's copy that over cuz we're just going to create two for now. So, we'll have an ID of two on this one and a name of bye. And down here, we'll just render out that name property. So, there we go. You can see everything's still the same. We have hi bye being rendered out. But, we actually have a problem with our code. Let's just inspect our page. I'll bring over the console real quick. And if we take a look at the console, you'll notice we get an error. Each child in a list should have a unique key property. This is something about React that's really confusing to beginners is that anytime you loop through an array, you actually need to put a unique identifier on the top element that you're returning, in our case this H1, and this top element needs to have a key property that is unique to that particular element. So, in our case, each habit has an ID, so we can put the habit.id on there. Doing that won't change anything with your code, it'll all look exactly the same, but behind the scenes React now knows which H1 is related to each element in your array. So, for example, if I remove element number two, it knows to remove just the second element and not change anything else on my page. So, it's really just there as a helper for performance. Or, for example, if I change my text to hi two, it knows only ID one is changing and that doesn't need to update anything else on my page, again helping out with performance. So, anytime that you're looping through an array of elements and rendering them to the screen, always make sure you add a key property and make sure it's unique to that particular element. Usually, you'll have some type of ID, but in the absolute worst case scenario, you can use the index property, just like this, of the array. I would just highly recommend not using the index property unless you absolutely have to because, for example, if you delete element right here from your array, now your index properties are no longer matching up to the exact same elements, so it can cause certain problems if your array content is changing, which is why I almost always recommend using some type of unique identifier, which you usually should have for each one of your elements. Now, obviously, inside of our array, we want to render not just an H1, but we want to render out this fully complex component with lots of different things going on inside of it. This is a situation where you can easily create a completely separate file and a brand new component. Or, in our case, what we're going to do is we're just going to create the component directly inside this file because it's kind of uniquely linked together. This habit item we're going to be putting in here is only usable in this list, so we're going to kind of have them both in the same file, but you could do this however you want, separate file, same file, it doesn't matter. So, let's come in here, we'll call this habit item, and this is going to be each one of the items inside of our list is going to be what we render here. And if we just return an H1 that says hi, and down here we replace this with our habit item, and we replace habit item here, you can see we still need to pass along that key property because obviously we need to pass a key anytime we're using an array. And we don't need to worry about setting that as a property for our function cuz again that's automatically handled by React. It is a name that is always there, just like children is always available, key is always available as a property. So now if we give that a save and we look over here, it just renders out hi twice cuz we're hard coding that value of hi. Now in our case realistically we want to pass down each individual habit, so we can pass down the entire object of habit to our property here. And again to make our code a little cleaner, we'll just make it self-closing. And now in here we can take in a habit property and we'll call this our habit item props as our type. And let's create a type for that. So we have our habit item props. We know that it has a habit property, and this property is just equal to whatever we have up here. So we're going to create an ID. We'll make it a string instead of a number, and we'll also come in here with a name, and that's going to be a string as well. So let's make sure that these are string-based IDs. There we go. And now you can see everything is working. All it's saying is that we need to make sure we use this habit variable. But this means that we can pass along not just strings and numbers and booleans, we can pass along full objects and even functions to other components. You can literally pass anything you want to another component. So now here I could put the habit.name, and it's going to now work just like it was before where it says hi and bye. Now in our case let's go ahead and style out what everything's looking like. And essentially we have two sections. We have this header section with all of our text and the delete button, and then we have our bottom section where we can like toggle what different days we've actually done this habit or not. So let's break this down. We're going to use a div to separate our two sides, and we're going to have a class name of rounded XL, background zinc 800, and a padding of four. Just like that. That's going to give us the space for our different content, and then we're going to have our header section as well as our footer or the buttons. So, our header section is going to be a class of flex. Items are going to be in the center, justify between, and we're going to put a margin bottom of three on the bottom of that section. And now if I just put some random text in here, you can see we have those sections and we have that little margin on the bottom. And instead of a margin bottom, I'm actually going to change this to a flex column with a gap of three just cuz I like using gaps rather than margins. And it's going to give us the exact same result, but you can see it removed that stuff cuz there's no content after here. If we add another div, which is going to be our bottom, you can now see it properly spaces those elements out. So, now let's go ahead and work on the rest of this header section. So, we have the layout of it done. Next, we want the title. So, the title is going to have a class here of font medium. So, it's a slightly more bold font, and that's going to be our name. So, our habit.name just like that. Here you can see we have our names being shown up just like we want. Next, we're going to have that streak section showing up. So, inside of here, we're going to come in with a span. Class name is going to be text small. We're going to use text amber of 400 just like that. And then we can put whatever our streak is inside of here. So, let's say it's a three-long streak, and we'll just use a fire emoji. You could obviously use a real icon in place, but we're just putting a hard-coded emoji. So, you can see we get that nice little fire streak of three. Now, we obviously want these elements to be touching each other. So, I'm actually going to wrap them in their own div just like this. And I'm going to make sure that they have a small space between each other of three and that they line up in the center. There we go. So, now they are touching each other with a very small space between them. Next, we want to add that button for delete right over here. So, we can come in here using our same exact button component. And what we're going to do inside this button component is just put the text of delete. And we'll give that a save. And again, it's going to look different cuz we have a much different style button, but we're going to be using a lot of the same exact things in our original button. So, I'm going to be keeping this as is. And again, I'm going to come back to showing you how we can create this more custom version of the button by tweaking existing components, but it's a slightly more advanced feature. So there is our button section completely done. Now all we need is this bottom section for all of the different dates we're going to be rendering, and that can go inside of its own div just like this. And let's make sure we add a class name to this of flex with a gap of 1.5 to space out each button from one another. Now in this section, we could try hard coding seven dates like this, or what we could do is we could just loop through an array of all the dates that we have. So let's just create a thing called visible dates, and that's going to be an array for each one of the dates we want to render, and they're just going to be dates. So it'll be like new date, and that's going to be what the current date is, and then we get the previous date and the previous date and so on. So we want to render out all those different elements inside this section. So what we can do is we can say visible dates.map. I want to map through each one of our dates, and I want to render out some content specifically for each one of those dates. Now for each one of these dates, we can do that exact same trick with the parentheses, and we can return a button cuz again, we're using a button for almost every single thing in our application. We want to make sure we specify a key. In our case, the key is going to be our date converted to an ISO string that'll be unique for each individual date. And now what we can do inside the button is render out our content we want. And we don't need to just render out text. The nice thing about passing along children is you can render out other JSX or in our case HTML. So we can render out for example a span that's going to contain a class name of font medium, and then we can come in here and we can format whatever we want for our particular day. So I'll just put two for now. And we can do the exact same thing down below. This is just a normal span, not bolded at all, and we can put out the text we want. So this is like Monday the 2nd for example. Now if we come back to our application, you can see it's rendering out Monday two, Monday two. That's cuz we have one date being rendered. If we had multiple dates inside of this section, just like that, you can see it's rendering all them out and spacing them out from one another. Now obviously, we need to make sure that we format our button to look proper cuz right now it looks completely different than the button in We also need to make sure we do all of our date handling properly. So, I'm going to be installing a library. This library is called date-fns, and this is just a library that makes working with dates so much easier inside of JavaScript. So, now what we can do is we can use a bunch of different helper functions to get all the code we want. For example, if I wanted to render out the current week, I could come in here and I could say start of week just like that. Make sure that this gets imported properly from the library from date-fns. And this is start of week. This is going to give me whatever day is the start of our week, so I can say start of week like this. That's going to give me the very first day of the week. And then we make sure we pass in the week we want to handle. So, I pass it in a date, and it's going to return to me a date that is the current start of that week. I can also get the end of the week, and I can get all the days inside of an interval. So, I can say each day of interval just like this. I can pass it in a start location, which is the start of the week. I can pass it in end location, which is the end of the week. Just like that. And now essentially what this is going to do, if I close off all my parentheses properly, is it's going to give me a full array that is going to start at the start of the week, and it's going to end at the end of the week that gives me every single day in between them. So, now if I give that a quick save, and I make sure I restart our application, we should hopefully see over here we now have 1 2 3 4 5 6 7 different days being rendered. Now, let's make sure we render our text instead of hard coding this. And for that we can use the format function which comes from date-fns. This function is really nice. You pass it in a date, so each one of our individual dates, and then you can pass it a bunch of different format strings. You can look up all of them if you want, but if you type in three E's, that's going to give you the day of the week as a nice little three-letter abbreviation. We can do the exact same thing down here. And if we want to get the day of the month, we can just pass in a single D, and that's going to give us the day of the month. So, we have 5 6 7 8 9 10 11. Now, in our case, I want the week to start on a different day. So, we can say here that we want to have the week start on a one and that's going to start the week on a Monday instead of a Sunday. So I can do that for both and now you can see our week starts on Monday and ends on Sunday. So we get that nice full 7-day list right here. Now let's go up to our habit list. We're going to remove all but one of these elements we just have our very first one so it's easier for us to take a look at. And now what I want to do is I want to do what I've been talking about this whole time is making it so we can customize the code being passed along to our button. So we can get all of our different styles for our element to look exactly as we want to. For example, I want to disable some of these buttons that are in the future and I also want to make sure that my styles are proper. So let's first take a look at how we can pass along disabled. So I can come in here, I can say disabled just like that in my button. I could take in the disabled property which is a boolean. So I can get my disabled property and I can pass it along directly to my button. So essentially I'm just forwarding this disabled property onto my button just like this. Passing it to my button here, passing it to my normal button. And now if I come into my section and I make sure this is an optional property that defaults to false, that'll clear up all my errors. Now if I come into here, I can pass disabled and you can see all my buttons are disabled because I passed along disabled. And I could even make it so it only disables the future ones so I can say is future and I can pass it in my date just like that. And now all the dates that are in the future, for example Friday, Saturday, Sunday since I'm recording this on a Thursday, are going to show up grayed out while all the dates that are current or in the past are going to show up not disabled. But this is kind of cumbersome especially if I want to pass along a bunch of different properties. Because if we take a look at button and we just hit control and space, these are all the properties available to a button. You can see there's just a few of them. So if I wanted to have to manually pass every single one of those by passing the prop here, putting the props up here and then putting it down here, that is a massive pain to deal with. This is why inside of React, they actually give you a little helper that lets you access every single property that is available on an element. So what we can do is we can add on to our existing button properties another set of properties and this is going to be called component props. And inside of React, this is a generic where you can pass it along any component. It can be a custom component or it can be a string of any existing HTML element, in our case a button. And what it's going to do is it's going to essentially give you all of those properties as accessible from this element. So here, if I just come in and I go ahead and disable, you can see it's there. And you can see every other HTML property I could add to a button is now available in this section. I'm going to group all those into one element just called props, so I can say props just like that. So now I have a single variable that includes every single property that's available on our button element, and I can just pass those down just like this. So by wrapping it in the curly braces, that's passing down to JavaScript. And if I just put dot dot dot followed by this giant object, it's going to take every single property in that object and essentially it's going to do this. It's going to say disabled is equal to props.disabled. And it's going to go through and do that for every single property in this object. So for every single property I can pass down, it sets every single one of them. That's what this code right here is doing. And since by default buttons have a children property already defined on them, that is actually included in this props right here. So I don't even need to pass along my children at all. I can just close this off, and it's automatically going to pass down the children for me by just saying children is equal to props.children just like that, which is going to set the children in my element just the same as if I passed it along inside of the body of my element. And you can see everything still works exactly the same when I did this specific code right here. And I don't even need this children section right there at all, cuz again it's automatically handled for me by the React component props. And now here, I can pass along any custom properties I want to. In our case, I'm going to create a property called variant, and this is a variant that's going to be how I determine what my button looks like. Am I going to have a primary button, secondary button, and so on. So I can come in here with a button that's going to be primary or it's going to be secondary, or I'm going to have what's called a ghost destructive. And that's going to be representing our delete button. If we look at the delete button, you can see it says like red button that when we hover it, it gives us the red background. That's what ghost destructive is. Secondary is going to be these gray buttons, and then primary is going to be any of our purple buttons. So, we can fine-tune what our colors look like based on these variant properties we passed in. So, now I have this variant property. I can do whatever else I want with. Now, by default, I'm going to make this variant property optional, and it's going to be set equal to primary as the main value for it. And now, I want to create a simple function that is going to give me my custom CSS styles. So, let's call this get variant styles, just like that. This is going to take in my variant, which let's create a custom type for. And let's just copy all that over to there. Perfect. So, it's going to take in whatever my variant is, and then I want to do a simple switch statement on that variant. And the reason I like to do a switch is cuz at the bottom, I can put a default case, and this default case is just going to throw a new error. And it's going to say invalid variant. And I'm going to put in my variant, just like that. And the nice thing is I can say satisfies never, and if I'm using TypeScript, this will give me an error unless I handle every single case in my variant here. And if you want to learn more about this satisfies keyword and everything related to it, I'll link a video in the cards and description going over in depth why I love this property. So, now I can come in here with each case. I need to make sure I handle them all. So, we'll start with primary, and I want to return some CSS styles. So, we're going to say background is going to be essentially our default background and hover. So, I'm just going to copy that, paste it into here. Next, we're going to do the exact same thing for our other two cases. So, we have our secondary. Our secondary case is going to be a gray color. So, we'll say zinc of 700 is going to be what we want our background to be. We want our hover background for this one to also be zinc. So, we'll say it's going to be a zinc of 600. And then we also want to change our text to be a zinc of 400, so it changes everything related to that. And then And we want our ghost destructive, and this is going to be a red color, so we're going to say background red, and this is only when we hover. We want our background red to be 800, so nice bright or dark red background color. We also want to make sure that our text is a red 800 by default, and then finally, when we hover, we want our text to be a red of 200, so it's going to be a very bright red, while this is a dark red color. Now, the nice thing is we can take this get variant styles function and put it directly into our class names. So here, again, if you want to run JavaScript, pass it inside of curly braces like this, and then we want to use string interpolation, so we're going to use these backticks, and then we can pass along our function and our variant directly into it like this. And there we go, we've now added all those class names directly to the start of this list right here. So now, if we take a look at our buttons, they all still look exactly the same because they all have a default variant of primary, but if we wanted to change some of these, for example, in my habit items, so let's go into our list here, and our delete button, which is inside this section right here, let's say I want to change the variant on this, and I want to change it to that ghost destructive, just like that. Now, if I give it a save, you can see it gives us all those red styles, cuz essentially, that's what we're doing in our button, is we're getting these red styles when we pass in a specific variant. This is a very common thing that you're going to do inside of React is essentially add in variants to your components, so you can use one component that shares a lot of the same stuff, but you can do slightly different stylings or different features for it based on these different variants and so on. Now, another thing that I want to be able to do is pass along custom class names to my buttons. So for example, this add habit button, I can make slightly bigger, or these buttons I can make stack vertically instead, and since my component props for buttons already has a class name, I can actually just take that in like this, it's already available, and now I can make sure I pass along my custom class names to this pre-existing class name section as well by just putting them at the end like that. So now, I can add on my own custom class names as as as these existing variants right here. So let's go back into our habit list. And actually, let's just go into our habit form cuz this one's going to be relatively easy to add our different classes to. I can come in here with class names. And for example, I could change the background to red 500. And if I save, you'll notice it doesn't quite look like it's working. The reason that it's not working is because I have this background red 500, and I'm also inside my button applying a background violet 600. And Tailwind doesn't have like any specificity or anything. It just defines whichever one is last in the CSS, and violet happens to be after red. So, that's why it's not showing up as a red color. Instead, I need to use a custom library called Tailwind merge. This is only useful if you're using Tailwind, but since a lot of people use Tailwind in React, that's why I'm using it. And if you're using Tailwind, you essentially need this library. So, let's go ahead and install this library, and I'll show you why it's so useful. It's called Tailwind-merge, just like that. And now what we can do is we can merge together properties, and essentially it's going to take whatever's the last property we pass to it and use that one instead. So, here for our class names, we can use that Tailwind merge function. That's the only thing that comes from this library that we're importing, the only thing we care about at least. And what we need to do is we need to pass it our default styles that we want. So, we're going to pass it our variant styles, and we're going to pass it all of these other custom styles as well, just like that. So, the very first property is our variant styles, second property is all of our custom styles here, and then our third property is going to be our custom class names we want to overwrite everything with. Just like that, we give it a save. You can see first thing is this, second thing is this, and third thing is this. Technically, it should probably be in this order. And now essentially what's going to happen is it's going to take all of these styles and apply them. Then it's going to look in this variant styles, and if any of the styles in here are clashing with the styles in the first section, it'll take the ones in the second and overwrite the ones in the first. It'll then do the exact same thing with the class name here. It'll take any of these classes and overwrite anything that was defined before. So, our red color should be defined last, so it should be overriding all the the of our colors. So, let's go ahead and test that. Let's actually just restart our application. We should actually immediately see that now our button is that red color. So, it is overriding everything just like I expected it to. And no matter what we do or order we pass things in, it'll always use these class names to override anything that existed before. Now, in our case, I don't want to make it so this is a slightly bigger button. So, I'm going to give it a little bit of extra rounding by saying rounding of large. I'm going to give it a little bit of extra padding. And then I'll just make it so the font is bold. And actually we'll use medium for that. So, you can see we just made a slightly bigger version of our button, but otherwise it works exactly the same. And we're able to do that by essentially using that Tailwind merge to merge everything together. Now, if you're not using Tailwind, you don't need that Tailwind merge, but a similar concept applies. Now, let's go ahead and work on the rest of our items in this habit list because once we get that done, we can start working on the more interesting part, which is adding functionality to our application. So, inside this visible date section, we want to add a bunch of classes to our button to make it work like we want. For example, we want it to be flexbox based. So, we'll come in here with a flex, a flex of one, and a flex column. By adding flex one, it just makes it span the full width. So, for example, if we remove that flex one, you can see they don't span the full width. Flex one forces them all to span the full width. Then we have a flex column so that it's going to be vertically stacking our items. We want to also put our items in the center, and we want to have a very very tiny gap of 0.5 between our items. We'll make our buttons slightly more rounded, and we'll change the text to be quite small inside the buttons. And you can see already that's given us pretty much exactly what we want compared to what we have over here. Everything looks essentially exactly the same. The only minor difference is that our button up here for the delete, we'll add a custom class name to make the text extra small, and that should be exactly the same now between both of these different sections. And actually, I think small text is probably enough. And now you can see these are exactly the same as the other one. So, we've got the entire styling of our application done. Pretty much the only thing that we have to do next is to actually make sure we get the functionality working, which is the much more enjoyable part. Now, the first thing to understand about functionality in React is that everything runs through state essentially. So, if we go into our form, this is going to be the easiest place for us to add a different piece of state because we need to be able to track what this input is and then use that data when we click on this add habit button. So, let's go ahead and we'll keep a piece of state to track what the value of our input is. So, we can create a state variable by using the use state hook in React. This use state hook takes a default value. We'll pass it an empty string as our default value. Anytime you use inputs, always make sure you pass an empty string as the default value. And this use state hook actually returns to us two values in the form of an array. It's going to return us the actual value of our state, which we'll just call name, and then it's going to return to you a function you can use to update the value of your state. So, we can say set name, and that's going to be the function we call to update what this state variable is. So, now we have our state variable and a way to update that state variable. So, inside of our input, what we can do is we can say that our value, which is the value of our input, we can set that equal to our name property, and now we've essentially hooked up half of our state. We have hardcoded the input value to always be equal to whatever our name is. But now, I can't actually type in this input because my name value is hardcoded as the value, and it's always an empty string. We're never updating our name. In order to update our name, we can come in here with the on change event listener that'll fire every time we change our input, and we can take the event and we can call set name, pass it along our e.target.value. This is just whatever the current value of our input is. So, now we have this state variable called name that is being updated every single time we type in our input, and then it's putting that value back in our input. Now, if we type, everything works exactly the same as it did before. But the reason this is really useful is because now we have this name variable, and we can use it anywhere in our application. So, let's just come in here and just randomly place down our name variable just like that. So, now if I start typing, you can see that name variable is automatically updated every single time I change it anywhere I use it in my application. I'm just using it in one place, but it's being automatically updated. And that's the important thing to understand about React is state is the one thing that causes your application to re-render. So, the way React works is kind of different than like JavaScript and that it's a reactive declarative language. So, we declare what our UI output should look like and then every single time something changes in our state, it re-renders everything and reacts to those changes. So, essentially what's happening is the first time you load this page, it runs all the code inside these statements for return and returns exactly what there is. And then it stays like that forever on your page until your state changes. Anytime you change state, it takes all of your components that are within this state section, so all of this code right here, it re-runs all of that code with the brand new state variable and then updates everything in your UI. So, when our name changes, it re-runs all the code inside of here, it says, "Okay, my new name variable is this." Places that in the HTML and then re-shows that to the user. That's how everything in React is going to work for you. So, it's important to understand how state works because it is the one way you cause your application to re-render and make it actually reactive, which is what makes working in React so enjoyable compared to something like JavaScript where you have to manually keep track of what needs to change every time a variable updates. React is just automatically smart enough to handle all of that re-rendering for you, which is what I really love about it and what other people love about it as well. So, now we have the ability to add this name variable, update it, but we aren't doing anything with it. We want to make sure we add a new habit with that particular name variable. So, inside of our form, we can just create an on submit event listener. We can call this whatever we want. I'll call it handle submit. We'll create a function for that, handle submit. We know this takes in an event and this is going to be a form event. Make sure we get the correct form event. And actually, it's been changed to submit event. There we go. So, that's going to be the event for our form and we can just say e.prevent default, just like that. And we are getting an error and that's because I need to make sure I get the submit event specifically from React. When I import the React version, that's going to clean up all of our types. And by preventing the default, it just makes it so that when I click submit, it doesn't automatically refresh my form. If I actually remove that and I click on add habit, it's going to refresh my whole page and try to do a default form submission, which is not what I want cuz I want to handle this myself. Now, I can come in here and just console.log our name. So, now I can type in a name here, click add habit, and if I look at our actual page, go into the console, you can see that is being printed out right here as my default value. And that's great, but I want to be able to do something with this value as well. Let's first, before we handle that, deal with the rest of our application cuz here I can make this disabled if my name is equal to an empty string. So, if I say name.trim is equal to an empty string, well, then I want to dis- disable this component completely. So, let's come in here, just like that. So, now if I don't have any content, it shows that button right there. And I can just say if my name.trim is equal to an empty string, then I can just return as well, just so I don't actually do anything if I have no data to submit. Also, after I submit my form by clicking this button, I want to clear this input, so I can just say set name, set it to an empty string. And now, when I click submit, it'll clear out my input, I can type something new, click submit, clears it out, and that works just like we expect. Now, in order to use this name property to add a new habit, this is where we actually get to some of the more confusing parts of React because I want to add a new habit. Inside this habit form is where I want to add it. But, I'm using those habits in other parts of my application. For example, I'm using them in this habit list right here. There's no way to talk side to side to different components. I need to only be able to talk to components that are children of mine or be able to call functions that come down from the parent. So, essentially, to store state that can be used in both the habit item and inside the habit form, I need to store that in a place that has access to both of those components. And in our case, that is the app component. It's the only place that has access to our form and our list. Essentially, you just need to go up high enough that you're at a level that has access to both of the children component, even if they're deeply nested. That doesn't matter. So, now here is where I want to store my list of all of my different habits. So, I want to have my habits here and I want to be able to add a new habit in my form and pass down my habits to my list down here. Cuz right now my list has my habits hardcoded. I actually want to get rid of that and make it so that my habits are passed into this component so we can say that we're going to get the props habit list props. And let's type that out. And here we just have habits, which is that type of habit, and we want to get an array, and I don't think I typed out my habit. So, I'm going to create a type for that. There we go. And down here, let's just make this a type of habit. That way all of our types line up. So, now we can pass our habits into our habit list. So, right here, I can pass in my habits just like that. And right now, they're just a default empty array with no data inside them. Now, in React, if you want your application to react to changes, for example, changes to this habit variable, we need to use state. So, I'm going to replace this with a call to use state. And by default, we'll set it to an empty array. And then, like I said, this returns two objects, the ability to set our habits and the ability right here to update our to get our state value. Now, right now, this is just going to be an empty array of never values. We need to be able to type what this value should be. And we know that it should be a habit array, just like that. So, we need to get that habit type and export it. So, let's just go into here and we'll export the type for our habit, and we will import that right here. So, now we know that this must be an array of different habit values, and everything is working just fine. But now, in my habit form, I want a way to add a new habit from here. Essentially, I just want to call a function, add habit, pass it in a name, and have everything work. Well, we can actually do that. This function can be passed down into this component. So, we can have this add habit function. And we can pass it down. Let's just make sure we type this out. This is going to be a function that takes in a name, which is a string, and it's going to return nothing, so void. Now, we have a function that we can use to actually add a habit to our page, and we can pass that down from our app right here by just saying add habit. And let's just create a function with that name, so we can pass it down. There we go. This is going to take in a name, which is a string, and then we can do whatever we want with that string. For now, we'll just console.log the name. So, this looks like I've done a lot of convoluted stuff, but really all I've done is I've taken this habits code that used to be hard-coded in our list and used to be inaccessible from our form, I put it in a location that is shared by both of these elements, so now I can pass the habits down here, and I can pass down a way to update it into our habit form, and that allows me to update our data from this location and to be able to use it inside of this habit list location. Essentially, anytime in React that you want to be able to use components or state, you need to be able to put that in a location that's accessible by both those components that are trying to use it. And if you want to update state that is inside of a parent, for example, this habit state is in our app component, which is a parent to our form, anytime you want to update state, you must pass down a function that allows you to do that state update. So, in this add habit function, this is where we can update our state. So, for example, I could say set habit, and I can pass in whatever my habit is going to look like inside this component. Now, a very, very important thing to understand about a React is that state variables are immutable. That means you cannot change this habits variable except for by calling this function. So, if I were to do habits.push, and I push in my name like this, you would think, "Well, that'll add my name to the list. I just need to make sure I give it an ID. So, we'll say crypto .randomUUID, and the name will be set to our name. That adds a brand new habit to my array, and you'd think, "Well, that's all I need to do. That should work just fine." But, if I type in here, add a new habit, and click enter, nothing actually happens. And that's because, like I said, mutating state does nothing. React does not care if you change the state, it completely ignores it. The only way to get it to update is by calling set habits. So, you may think, "Okay, we'll add the new array, and then we'll pass it into here just like that." Now, everything should work fine, right? I type in my value, click enter, and again, nothing actually happens. And the reason for this is because the habits array is the exact same reference to the previous array that it was before. The way that state happens for checking if there should be an update or not is it takes your old state value, so we'll say old, and it compares it using triple equals with the new value. So, essentially what's happening is it's saying habits is equal to habits. These are both the exact same array, even though they have different values, they reference the same location. So, they're both the exact same array, so this is returning true, so there's no state to update cuz it's still the same. Instead, what you need to do is you need to return a brand new array inside of this section right here. So, what we can do is we can take all of our habits, and then we can add a brand new habit to the very end of this. Now, what this is going to do is it's going to make sure that it updates our habit array with a brand new habit at the end, and it's always returning a new array, so React sees this as a new array, and re-renders the component accordingly. So, let's just come in here, I'll add something, one, two, three, and you can see every time I'm adding something, it's adding it to the end of my array, which is exactly what I want. Now, let's refresh just to get us back to a starting point with just one element, and I want to talk about a potential bug that we have inside of our code. Anytime that you're using the existing value of state inside your state updater, you need to make sure that you're actually changing how your code works by referencing the second version of the set habits function. Let me show you the potential bug we're running into. Let's say that I want to add my array or my habit to the end of the array twice. So, I call set habits once adding it and then I call it again adding it a second time. So, I would think this would add my element to the array twice. But in reality, it only adds it once. You can see if I refresh my page, type one, it only adds it one time not twice. This is because this habits value right here is always the same. The page doesn't re-render until after all of our set state changes have been made. So, it takes all these changes, batches them all together, and since our habits value is the same between all of them, it only adds it one single time. What we need to do is actually take in the previous value or the current value of our thing. So, we'll call this current just like this. And this is going to take in a function that's then going to return our new state value. So, we can take our current value and we can pass it along our new value which is that crypto.randomUUID and our name just like that. Now, if I do this twice, it'll actually add twice to my array. So, let's refresh here and I'll just type in two and you can see it adds it twice. And that's because the first time this function is called, the current value is equal to our current habits array. So, it has nothing and it's adding on this one new element. The next time this is called, again it uses the most current up-to-date value which is the array with one element. It then adds another element. So, now we have two elements inside of our array instead of just one. This is very important. Anytime that you're using the existing value of state, always make sure you use the function version to get what that existing value is. You can't just rely on using the state value here. So, if you're using the existing value of state, always use the function version. But, if you're not using the existing value, for example in our form here, we aren't using the existing value of our name, we're just completely overriding it, it's perfectly okay to use the non-function version in those cases. You only need the function version when you're trying to use the existing value of state to update itself. Now, the next thing we need to be able to do is delete a habit as well. So, let's create a brand new function for that. We'll call this one delete habit, and we can say that we want to update our habits. And for this one, it's going to be very similar. We need to use the function version because we're updating the existing version, and this will take in an ID for what we want to delete. And all we want to do inside of this section is take our current list of habits, and we want to filter it for the habit where the ID is not equal to whatever ID we pass in. What this going to do is essentially remove the one habit where the ID is equal to the ID right here that I pass in. So, now I can use this delete habit. In our case, we need to use this inside of our habit list and inside of our habit item. This is where I want to use that delete habit. So, this delete habit takes in an ID, which is a string, which returns void, just like that. And when I click on my delete button, I can just say on click, it's going to call delete habit. And the way that you use event listeners inside of React, I guess I didn't quite mention this, is you want to make sure that you just take whatever the event is, prefix it with on, and then everything else after that is going to be camel case. So, on click, on mouse down, on submit, and so on. Now, in our case, we need to make sure we pass the ID to this. So, we're going to come in here, and we're going to say habit.id. That means when we click on this button, it should delete our habit. We also need to make sure our habit item takes in that delete habit. And we also need to pass that down to our habit list. So, we can say delete habit. Whoops. I'll just copy over what we had down here cuz it's exactly the same. There we go. So, now it's passing it down from the list into the item. And inside of our app, we need to pass it down as well. So, we can say delete habit, just like that. And now, hopefully, that should solve our problem. Let's type in one here and click delete, and you can see it does remove the element. So, it works just like we expected to. You notice there's a bit of a slight issue though, is that I need to access this inside of my habit item component, right? That's the only place I'm using this to habit. But, in order to pass things down in React, you must pass them from parent to child, from parent to child, and onward. You always have to pass it down. So, that means in my app, I pass delete habit to the list. The list never uses this function. All it does is pass it down to the next child, which is the habit item, and then finally in here is where I use that actual function. This is what's called prop drilling. Essentially, it's the idea of passing down a prop through multiple components, even though none of those components use it except for the very last one. This is a problem that we can solve with context inside of React, which I'm going to be showing you how to do in this video, but for now, I want to get everything else in our application working before we move on to handling this with context. Now, really the last thing that we have left for our functionality of our habits is making it so when we click on these buttons, we can toggle between a state of active or inactive. To do that, we need to keep track of all the times we've completed a habit or not. So, inside of our habit type, actually we need to add another property, and this is going to be for completions, and this is going to be an array of all the dates where we actually completed this particular habit. Then, with that completions data set, I can come all the way down inside of my dates, and I can change essentially what I render based on if I've completed this or not. So, I can change my variant, and I can say if I've completed this, I want to render out the variant. So, I can say habit .completions, I want to check if any of the dates inside of our completion, so we'll come here with a date, is the same day as the current day I'm rendering. So, essentially all I'm doing is I'm looping through every single one of my dates, and I'm checking is this date equal to whatever the current date is. So, I'll say date and D. So, D is each completion, and date is whatever the current date being rendered here is. So, if this is true, that means it has been completed on this date, so I want to render out the primary color, otherwise, I want to render out the secondary color for my element. Now, I am getting some errors, and that's because I need to make sure I pass in a completions array that is an empty array by default as each one of my elements. There we go. That solves that problem. And now if I type in one here, you can see all of these are grayed out cuz none of them have been completed yet. While if I add a completion date, so like let's say by default it says it's completed today. If I add something, you can see today has been completed but the rest of the days have not cuz they're not inside this array. So now let's go ahead and we're just going to add a simple function here for toggling a habit. So we'll say toggle habit. We're going to pass it in ID as well as the date we want to toggle for this and we want to update our habits accordingly. So for this one, it's going to be a little bit more complicated of a function so I'll put it inside of parentheses right here. And I want to take each one of my current arrays. I want to map over them. So we're going to have an H right here. Put that in parentheses and this one I'll actually use with the normal brackets so it automatically returns itself. There we go. And inside this section is where we need to return what the new value for our array is going to be. So in the past we've added and we've removed. Now to update the value of something, this is where map comes in cuz I can essentially return everything as is by just saying return H. That won't change anything. But what I can do is I can modify certain things based on different properties. So if our H.ID is not equal to the ID I want to pass in, I'm just going to return H as is. Essentially that's saying if the ID does not match, don't do anything, leave it exactly the same. Then what I want to do is I want to determine has this already been done? So have I already completed this? So I can check my completions and I can say are some of them the day that I'm checking for. So we can use that same is same day and pass it in the date from up here. This determines have I done this thing or not? If I haven't done it then I need to do specific things. So I can get what my new completions array is going to be by just saying already done. If I've already done this, I want to remove that completion. So I can say H.completions and I want to filter out where it is not the same day just like that. So what this is going to do is essentially going to remove that item from my array based on this completion section. And if I have not already done it, I want to add it in. So, I can say here h.completions and add my date onto that section just like that. So, now I've checked have I already done this? If I have, remove it. If I haven't, add it. And finally down here, we can return my object it's as is by just adding the completions property on just like that. And again, the reason I'm doing this in a non-mutable way immutable way is cuz React does not like it when you mutate state. So, I'm always making sure to make all these changes immutably by creating new objects and new arrays for absolutely everything. So, now I have this toggle habit function. I can pass this along and just like before, we need to make sure that we chain this along to all the different places it's going to be used. So, here toggle habit takes in an ID and a date. It returns nothing. Just like that. Make sure I take the same exact thing in here. Toggle habit. Up here, I need to pass that along cuz again, we have that prop drilling thing that I talked about. So, we pass that along and then finally all the way down here for our buttons, this is where I can call that by saying on click toggle habit. And now every time I click on this function by passing along the habit.id and the date, it's going to toggle for that specific date. So, let's just try this. If I click on eight, you can see it's now toggled true. Click on seven, it's toggled true. Eight has now been toggled off. So, every time I click, I can change whether or not these are true or false all because I'm passing this function down. It's being passed through the list items and then finally all the way in the app, it's essentially calling this which updates my habit state. And since this habit state is at the top level, it re-renders all of these children and it goes through re-renders of my header. It'll re-render my form and it'll re-render my list where ultimately those changes are being reflected. Now, the next thing we should probably do is make this streak value actually correct instead of hard coding it. So, we can just create a simple function called get streak, take it in all the completions, which is that date array, and I just want to essentially loop through these backwards until we find how many completions there have been. So, let's create a variable called streak. We'll set to zero. And we'll create a variable called date, which is going to start at the current date. And I'm just going to do a simple while loop. So, I'm going to say, while there is a completion that is the same day and date, just like that. So, I'm saying, is there a completion for the specific date that I'm checking? In our case, I'm checking the very first day, which is today. So, I'm checking, is there a completion for today? If there is no completion for today, it immediately exits out of here, and I can return my streak as is. Otherwise, if there is a completion, I just want to take my streak variable, add one to it, and I want to take my date, and I want to go backwards one day. Luckily, inside of date-fns, we have a function called subDays, where we can pass in a date and the number of days we want to subtract, and now I subtract one day. So, essentially, this starts with today and counts backwards every single day and checks, is it today? Is it today? Is it today? Is it the same? Is it the same? If it is, if you have a completion, it adds one to our streak over and over until eventually there's no completion, and it just returns what our streak is. So, here, I can use that streak. So, we'll just say, const streak is equal to get streak for my habit.completions, and then I can use that down here by just passing in what my streak is. So, now you can see we have a streak of one. If I remove this, you can see a streak of zero. Honestly, I probably don't want to render out a streak of zero, though. In order to conditionally render things in React, which is very important, wrap it inside of these curly braces like this, type the thing you want to check. So, if our streak is not equal to zero, then what I want to do, put double ampersand, and render out whatever content I want. So, just whoops, like that. There we go. Now, that'll only render my content if I at least have a streak value. Now, the reason that this works as is is because this double ampersand inside of JavaScript is a short-circuit way of doing an and check. So, if this returns false, it'll stop checking and not return this section right here. And in React, if you paste false in to try to render that out as actual code, just like this, false just doesn't render anything. You can see nothing shows up on my screen. So, the way that this code works is if the streak is equal to zero, this returns false. So, this essentially ignores everything after here and just renders out false, which we know doesn't show up. Otherwise, if our streak is not equal to zero, this returns true, which means it runs the code after here. So, essentially it's returning whatever this section of code is. And this is using short circuiting inside of JavaScript to handle this. You could also do a ternary syntax like this. That's essentially going to be the same thing, but this is a little bit longer-winded to write, which is why most people, when they have this true-false kind of dichotomy, write out the syntax like this and just rely on short circuiting to handle everything for you. So, now we've got the bulk of our functionality done. We can't really move backward and forward yet, but I want to fix some of the problems we have related to context, because right now this prop drilling really sucks. So, I'm going to introduce you to a context, which was introduced to solve this prop drilling problem. So, let's go ahead and we'll create a brand new folder called context, and I'll create a brand new file inside of here called habit provider.tsx. Often, when you're using a context, it'll either be called provider or context at the end. That's kind of a standard naming practice. We're going to export a function called habit provider, just like this. And this is going to be the essentially section that contains all of our context-related code. And context in React is a way for you to wrap a bunch of components and then give them access to specific state data anywhere they want without having to pass it down as a bunch of children. To do this, we can first create a context. So, we can say const habit context. It is best practice to make this capital, because it's going to be showing up in your JSX. And we can say create context, just like that. And by default, you're probably going to have a value of null as your first value. And then, you need to make sure you pass it a generic where the null is the first value and then the type of our habit context or whatever we want. So we can say like habit context type or we can just call it context. That's probably even easier. And then up here we'll trade a type called context which contains anything we want. Let's just put a name with the string for now. So essentially what I'm saying in this particular piece of code, if I actually write it out properly, there we go. Is I'm saying that I want to create a context called a habit context and it's going to either have a value of null, which is our default value, or I'm going to set it equal to a value of anything inside this context here. Now this habit context, what we can do is we can return this. So we're going to return this inside of our component here and we can pass along a value property and this value property is whatever I set for my type here. So you can see I can set a name just like that and whatever my type is here is what I pass along as my value section right here. And inside this habit context is where you pass all the children that you care about. So in our case, we're going to pass along all of our children just like that. We're going to take in our children as props. And we're going to say habit provider props. And we'll create a type for this as well. children And we know that is a react node just like that. There we go. So now that's taking on all of our children related content and now what I can do inside of my habit or my app page, I can wrap all of this code inside that habit provider. So I can say habit provider, wrap all of that code and now anywhere inside these components or the children of these components or their children all the way down to the very bottom of my application, I can access any of the values from my state that I define here. And the way that I do that is actually quite simple. So what I want to do, let's just go inside my habit item cuz I know I'm going to access some things inside of here. I can use a hook called use context and I need to pass it in the name of my context. So, let's make sure we export that from here. There we go. We now have our habit context being exported. And now what I can do inside of here is I can access that habit context. I can say habit context is equal to that. There we go. And now I have this variable habit context that contains all of my state variables. So, I can say habit context.name, and that'll give me access to that name property. This is very useful because I don't need to pass this name property down through the props. I can just immediately access it in the exact components I need to, which makes writing my code much easier. Now, obviously, we're not going to be using this name property or anything like that. So, let's come into here. Let's get rid of that export cuz we don't need it for now. And let's actually make sure that this type is what we expect the type to be. First, I want to have a habit array that's going to store all my habits. Now, I'm going to take my habit type, which I have all the way up here. I'm going to actually move this type into this file right here. Oops, not this file. Sorry, into the habit provider cuz this is the place that stores all my habit-related code. And then I want to have a section for add habit, which is going to be a function that takes in a name and returns void. I'm going to have delete habit, which takes in an ID, which is a string, and returns void. And I'm also going to have toggle habit, which essentially does the exact same thing, but it's going to take in a date as well. These are the three functions we created in our app. You can see we scroll up, add, delete, toggle. So, I'm going to take all the state and all of these functions, I'm going to remove them from here and put them into my context instead because this is the thing that's being shared throughout our entire application. So, we have our habits, our set habit, our full state, which make sure we import that, and then we have our functions down here. Let's make sure we import these functions we're using. There we go. And now what I can do in this value is I can pass all that data down. I can pass my habits. I can pass my add habit, my toggle habit, and my delete habit. And now anywhere at all inside my code, I have access to these variables as long as it's wrapped in this habit provider, which right here it is. So, all these places where I have these things being passed down, I no longer need to pass them down. Inside of here, I can completely get rid of this prop cuz again, it's no longer needed at all. And instead, I can get that from my context by saying my habit context is equal to use context and passing it in that habit context. And again, I need to make sure I export that. So, let's come in here. Export that. And we'll import it right there. And now, I have my habit context, and I could say here habit context, and I want to add my habit. And now, all of a sudden, everything is going to work fine. But, there is a slight problem with our code that's mostly just a syntax problem that we can solve pretty easily. You can see here this habit context could be null. Now, I know for a fact it's not null because I wrapped everything properly, and I made sure, if I get rid of these imports that are no longer needed, I made sure in my habit provider to give it a value every time. But, TypeScript's not smart enough to know that. This is where you usually, when working with context, will create what's called a custom hook. A custom hook is essentially your own way of creating a hook that does things in React just like all the existing hooks. And for example, use state is a hook, use context is a hook, everything that starts with use is a hook inside of React. So, what I can do inside my provider is I can export a function called use habit. Just like that. Oh, we say use habits. There we go. And this is going to be a custom hook that wraps our normal use context hooks and passes it in our habit context just like that. So, we're going to get our habit context. There we go. And now, I know that this could be null or not, so I can just say, if my habit context is equal to null, well, that's obviously not good, so we'll just throw a new error. And you can put whatever you want in here, null context. Sure, there we go. Doesn't really matter. And then down below that, we can return our habit context. By doing this, we've essentially removed the ability for this to be null, and now I can use this hook anywhere else I want inside of React. So, I can go into my app right here for my habit form, just like this. I can use that use habit hook instead, and now I get my habit context, which I can just destructure out the add habit that I want, and use that directly right there. So, that gets rid of all those null checks that I would normally have to worry about and makes my code much cleaner and easier to work with. And I can do this anywhere I want in my application. So, let's go into my habit list. We scroll all the way down to our habit item. This is where I need my delete and toggle. So, I can just come in here with delete and toggle. And I can make sure I import that custom hook. Get rid of those from here. Get rid of those from here. Make sure I import that habit right there. And now everything else is working exactly the same as before, but again, I'm getting it directly from the context instead of having to pass it down through prop drilling. I can again get rid of those here cuz they're not needing to be passed down through prop drilling. Get rid of them from here. And I can make sure to get my habits, I can just say const habits is equal to use habits, just like that. And now that gives me that habit information. And again, I don't need to pass this down cuz it's all being handled for me. So, it drastically simplifies my code by not having to do a bunch of prop drilling. And if I just clean up my imports by getting rid of all the things not used, everything should be working exactly the same as it did before. I can toggle things. I can delete things. Everything's working the same, but it's now all running through this context instead of being passed down manually through everything. And you can see it drastically cleans up what our actual code looks like. Now, you may notice inside of our habit provider, there are a few errors. If we scroll up, it essentially just says fast refresh only works when a file only exports components. This is something that only matters for development. So, while I'm developing my application, if I change a file, it'll automatically refresh my content on the side without redoing my entire page. So, for example, you can see I have this state variable right here and it's showing up and it's working fine. And if I were to change something in my code, for example, let's just change it so my streak starts at 10 by default, and I save, you can see it automatically refreshes all my page content without redoing my entire page. Now, let's go say I change something in my habit here where I don't have fast refresh enabled. Let's just say I make a small change, console.log here. And now I save this particular file, and actually let's make it maybe export some random content. So, we'll just say H1 that says whatever. You can see that that is showing up over here, and essentially it's just making it so that it has to do a little bit more work when it does the refresh. It's not quite as fast, not quite as quick. For the most part, it doesn't matter too much, but it can be a little bit annoying, and sometimes it'll actually delete your entire state and restart your state because it's refreshing things a little bit more. So, if you want to get around this problem, what you can do is you can just create another file. We'll just call this one use habits .ts. We don't even need the .tsx extension cuz we're only using plain TypeScript. I'm just going to take all the things that aren't a component and move them into this file. So, that is going to be our context just like this. And inside of our provider here, we want to get our context type as well. And now if we just import these particular things, there we go, and import habit, which we might as well just copy over from here. There we go. Now, what we need to do is just clean up all of our imports to import everything from there. So, here we have our habit being imported. Here we have our context being imported, so that all works fine. And then inside of our list here, I believe we just need to import these from the correct location. And habit from the correct location. And same thing here, this just needs to be updated from that new location. There we go. Let's refresh and see if that works. Looks like everything is working exactly the same it did before. Perfect. And again, this just solves that fast refresh problem to make it so you can refresh your components faster and it doesn't clear out your state which sometimes happens. Again, it's entirely optional if you do it or not, but if you want to do it, you just essentially need to make sure all your components are in their own file and anything non-component related is in its own file. And again, since this component doesn't use any JSX syntax, we don't need to add .tsx at the end. It can just be a normal TypeScript file. And the next thing that I want to work on in our application is to make sure that this one of one done today section is properly handled and that this previous next button work cuz right now they don't actually do anything. So, let's do this one of one section cuz that's actually a very easy fix. We just need to find in our code where that is, which is in our list. Actually, I believe it's in our header, so let's go to our header. Here we go. And you can see one of one done. Here, we just need to make sure we get our habit information so we can just say const habits equals use habits. And we can just say const done today is equal to habits.map. Actually, we can just do a filter. There we go. I want to filter for each habit where the completions includes today. So, we say some where some completion has today. So, we can say C is today C. There we go. I should make sure that's imported. So, essentially, this is going to give us an array of all the ones that have been currently done. I want to figure out how many that is so we can set that to a length. And then what I can do is just put my done today value here and my habits.length value right here. And now you can say zero out of zero done. Now it says zero out of one. If I mark today as complete, it's one out of one. If other days are complete, it won't show up until I mark today as complete. So, it's properly updating everything, which is just what we want. Let's delete that and now we can move on to this previous and next button section, which is actually also inside this component, but I need to be able to access those values down below cuz right now it's rendering the 6th through the 12th, which you can see right here. If I click previous, I want this to change and update to render everything the week previous. Or if I click next, it should render the week next. So, this is again state that I want to store a little bit more globally in my application. You could also put this in a context if you want. You can even put it in the exact same context. I'm going to show you what this will look like not in a context though, cuz some things don't always make sense to put in context. For example, our habit right here contains everything related to habits, which makes sense to show in a context cuz you could use this data in many places in your application. This little section for the previous next button is just a small UI thing. So, I'm going to leave this outside of the context cuz I think it was a little bit more sense to put outside context, but it's mostly up to you. So, we essentially need the week offset. And this is going to determine what week we are currently on. So, I'm on the current week, it'll be zero. If I'm backwards one week, it'll be -1, -2, -3, and so on. And we can set our week offset as well, cuz we're going to be using state for this. Since essentially anytime you want something to reset in your application, you need state. And the default value is zero, so it'll render out the current week. Then what I want to do is I want to get what the current weekdays are. We'll just create a function for that. We'll say get visible dates, which takes in a week offset, which is a number. And this get visible dates we've essentially already written. You can see it's right here. So, we can take all this code for our visible dates, and we might as well not even need a function for it. We can just pass it down just like this. There we go. And we can just say we want to get whatever our current week is by taking the add weeks function, passing it in our week offset, and getting the current date just like that. There we go. Now, let's make sure we use that week value inside of each of these. And let's import all these functions that we're using. There we go. And my add weeks just needs to be reversed in order. There we go. So, now essentially what I'm done is I've figured out what my week offset is, 0, -1, -2, -3. I added that to my current week, so if it's negative, it'll remove weeks from my array, and then I'm just passing that in and getting all the visible dates for the current week based on that old code that we'd already written before. So, now I have access to all my visible weeks, and I can pass those into the header to do whatever I want. So, I can say visible dates is equal to my visible dates, and in the header I can take in the visible dates. And let's create the props for that as well. And the visible dates is just a date array. There we go. So, now with those visible dates, let's render them out right here instead of hard coding these values. Let's actually make it dynamic value. So, what we can do is we can just say const date range is equal to I want to format my first day of my array. So, we'll say first day, which is just our visible dates of zero. That's the very first day. I want to format this using the month syntax abbreviated followed by whatever the individual day is. Let's make sure we import that format function from date-fns. There we go. And now we can use that date range, for example, down here just like that. Now, if we give the page a refresh and make sure here I refresh this as well, you can see it renders out April 6th, which is currently the day the the first day of the week that I'm recording this video. Now, let's go back into our header, and we want to add in the end date as well. So, essentially the exact same code as this, but I want to get the last value of my array, and to do that I can just use the nice little at function and pass -1. That'll give me the last value of the array, and technically it could return undefined if there's no data in the array. So, I'll put an exclamation point to say that I guarantee this will always exist. Now, you can see we have April 6th through April 12th, which is the current week that I'm recording this video. Now, essentially we want to be able to handle what happens when we click previous or next. So, we can create a function called on previous, which is just going to be a void function, and on next, and we can pass those along here. So, we can say on previous, we're going to call that function. And we can do the exact same thing here with on next. And I can make sure I take those in as props. There we go. So, now it's passing those along, and it'll call whatever these functions are anytime that I click on those buttons. So, now what I can do inside my app is I can create those functions. So, here on next, all I want to do is I want to take my week offset. So, we'll say set week offset. I'm using the current value to modify this cuz I'm just subtracting one or adding one. So, I want to get the current offset, which we'll call O, and I want to take O, and I want to add one cuz I'm going one forward into the dates. On previous is going to be the exact same thing, but I'm going to be subtracting one instead. So, now when I click previous, you can see it moves me back one week. Every single time I click this, it's moving me back one week on this list cuz I have this state variable, which is being updated. I'm then deriving new state variable information from that, and I'm showing that to my screen. And this is actually a very important thing to understand about how this code works is we are using derived state. Essentially, I have my state stored in React. That's my main state. And then this set of visible dates is being derived from this state that's stored in React. Many people, especially beginners, would think, "Well, I should probably store my visible dates in the state." So, they come in here with visible dates, and they put that inside a state just like this, and you know, they have the array. They do that kind of code. So, now they essentially have two things being stored in state. They have the week offset and the visible dates being stored. And if one updates, the other needs to update, and it's very easy for these to become out of sync, and now all of a sudden you have problems in your application where your state is out of sync with each other. So, if you have state that is derived from other state and doesn't need any other further output or input to it, just make sure you use that as a variable in your component like this. State should only be used for the things that are changing in your application and that cannot be derived from already existing state. If you have a variable that can be derived from other state, it should be stored just as a normal variable, which will automatically get updated by React for you. Essentially, you should never put state that is derived from other state inside of your state because now you have two things that are essentially competing with each with each other to say the exact same thing. Now, inside of our header, we want to make sure that we can't go to future dates cuz that doesn't make any sense since we haven't completed those yet. So, I can just come in here with a simple disabled property and I can just say this is going to be equal to if our visible dates dot some of them Oops, some of them include a day that is today. There we go. So, if any of our visible dates are today, then it should disable our button. So, you can see this is currently disabled and if we go backwards, it's fine, but as soon as we start going forward, you can see if any of those dates are today, it's going to be disabled. Now, let's go back to our app because we have these visible dates and we need to pass those down to our list as well. So, we can say visible dates is equal to visible dates and in our list, we need to take in those visible dates. So, we'll say habit list props. Oops, habit list props. Visible dates is just going to be a date array. There we go. And then what I can do is I can pass those down to my habit item cuz that's the place where actually going to be using it. So, again, you could do context here if you want to avoid prop drilling, but for this very small amount of prop drilling, I think it's perfectly okay. Here we're going to have visible dates, which is a date array, and now here, I don't need to keep track of my visible dates cuz it's being passed in for me. So, now they should sync up. Let's say pass in one here, you can see 6 through 12. If I go backwards, now we can see we get the 30th to the 5th and this is perfectly synced up between all of them and if I check one of these and I check couple of these, I'll say I go back here and check a couple of these, check couple of these, you can see it properly syncs all that data up, which is exactly what I want. Now, let's just go ahead and clean up these imports that we don't need. That'll get rid of any errors that we have in this file. And now what I want to do is to make sure our data is saved locally. Right now when we refresh our page, everything goes away. While in this example, if I refresh, everything stays there because it's being stored inside of local storage. And that's what I want to implement next inside this application. To do this, we're going to be creating a custom hook. So inside of here, let's just create a folder called hooks. And inside of here, we're going to create a hook called use localstorage.ts. And again, we don't need .tsx cuz we're only using plain JavaScript and TypeScript, no JSX at all. We're going to export a function called use local storage. And this use local storage is going to take the key for the name of the location I store it, as well as a initial value, just like that. Now, the type of this initial value is going to be T, and that's because this is going to be a generic function because we could store anything at all that we want inside of here. Now, before we start implementing this hook, I do want to talk about some rules to hooks inside of React as well as custom hooks themselves. Every single hook inside of React, use state, use context, use effect, and so on, they all start with use. So, use is the keyword you know that you're using a hook if it starts with use. And in React, every single hook must be defined at essentially the start of your file. You can never have a hook that is conditionally called. So, for example, I can't put a hook inside of an if statement. This is going to cause an error inside my code. If I have a hook inside of an if statement like this, immediately you can see it's called conditionally, it's going to throw an error for me. Also, I can't put them inside of for loops, that's going to give the exact same thing. They're called inside of conditional loops, can't put them in while loops, and I can't even put this after my return up here cuz again, sometimes this returns, sometimes it doesn't. So, this is again a conditional thing. This means that almost always, if you're using a hook in React, it should be the very top thing inside of your file. So, in our case, this is the very first thing I call, and in all my other components, you can see all my hooks are the very first thing at the top of my file, and then the rest of my code comes after that. So, it's very important to understand the rule of hook is it must be before anything else. You cannot have it be conditionally rendered or inside of a for loop or anything like that. Also, when you create a custom hook, it must start with the word use. That's how React knows to use a custom hook. And that's because hooks, such as use state, use context, and so on, can only be used inside of React components or they can be used inside of a custom component. That's why you need to start it with use. Otherwise, React does not know that this is a hook and it won't be able to do all the rules properly. So, when you create a custom hook, start it with use. And whenever you're using any hook, custom or not, just put it at the very start of your component, and that's going to work just fine for you. Now, inside this hook, we want to essentially get our data and store it in state, cuz everything inside of your component should be stored in state. So, we'll just come in here stored value, set stored value. That's going to be equal to use state. And by default, we can pass this in as the initial value. But, we actually want to do something slightly different, cuz we actually want to try to get the data from the local storage first. And if it doesn't exist, then we use this initial value. And this is where we can take advantage of the second way you can use use state, which is by passing it a function instead. So, we can actually pass a function to use state. And the only difference between these two is that the function is only called the very first time your component renders, and then it'll never be called after that. And the only reason you do this is for performance reasons. For example, want to check local storage every time my component re-renders. I only want to do that the very first time my component renders. So, by passing it a function, I make sure the code in here is only ever called one time to save me on performance. So, now what I can do inside of here is I can get my item from local storage. I can say get item of that key. And we'll just wrap this in a try catch in case there's any errors with our code. So, inside of our try catch, we can just return our initial value. So, if there is an error, just return the default value. Then, we can do if our item is equal to null, that means there's nothing in storage, so we can return our initial value. Otherwise, finally, we want to JSON.parse this data. So, we can say JSON.parse our item, cuz that's because we're going to be storing our data as a string, and we need to stringify our JSON and then parse it back out. So, if we have any data being stored, it'll be parsed back out of our application. Then, what we can do down here is we can return our value that we want to be able to update, and I'm actually going to be returning this in an array of value and set value. And actually, it's called stored value and set stored value, just like that. And I'll put it as const at the end here to make sure that TypeScript knows this first value is specifically related to this, and the second value is specifically related to this. Now, our use state variable is of that type T, just like that, and that solves all of our typing-related issues. And essentially, I'm creating a thin wrapper over top of use state. You can see I'm returning my setter and my getter exactly the same as before. I'm just making sure when I access my data, it tries to access local storage first. So, now if I go into anywhere I'm storing my habits, which is in my context, I can replace this with use local storage, and I pass along a key. We'll just say habits or something along those lines. And now, everything should work exactly the same. All of my data is there. If I change this data and I click add, you can see it's being added, so everything's working the same, but when I refresh refresh my page, it's still not storing my data in local storage. It's able to get data out of local storage, but it's not able to store data in local storage yet. In order to store our data in local storage, we're going to be using a use effect hook. This is one of the most confusing and most misunderstood hooks inside of React, so I will try my best to explain it to you as best possible, but essentially, this hook takes two properties. The first is a function, and this is the thing you want to run, and the second property of this is an array of all the different dependencies. And essentially, I'll get to what that means in a little bit, but the whole idea of use effect is this is when you have state that changes and you want to run a side effect because of that, this This the use effect hook comes in. So, in our case, every single time this value changes, I want to run code that saves that value back into local storage. So, what I can do is I can say every time this value changes, save it in local storage. So, I can say local storage.setitem for my key, and I can just stringify what my stored value is. Now, just by running our code as is, you'll notice if we refresh our page, everything is working just fine. If I type in some data, click enter, everything's working perfectly okay as we expect it to. But, if I refresh, it's still not storing that data. And that's because a use effect, like I said, only runs when your dependencies change. And since we're passing an empty array, that means this use effect runs once when my component renders, and then it never runs again. So, it's only running one time. I want this to run every single time my values change for my stored value. So, I can put my stored value in here, and now every time my stored value changes, it'll run this hook. So, now if I come in here, I type something in, hit enter, and I refresh my page, you'll notice that that data is properly being shown on my page, and it's being persistent. If I add something else, refresh, that stays there. If I delete this, refresh, all of that's being stored. Because every time my stored value changes, it runs this code right here, which saves that data in local storage. And then when I refresh my page, the first time it runs, it calls this code and gets my data out of local storage. Now, we are still getting a warning here, and that's because key is not listed in this array. Essentially, anytime you use a value in use effect, it should be in your array. And since we're using our key here, we also want to put that inside of our array as well. So, now anytime our key or our stored value changes, it runs the code inside of here and does whatever we have listed. In our case, it's just storing data inside of local storage. Now, there is technically a problem with our code. If we just select a couple of these dates, and then we refresh, you'll notice it still kind of looks like it's working, but the problem is is that it doesn't quite get our date information properly. Because when you stringify a date, it turns into to and when you parse it, it's still a string. So, we actually need to pass along a function here. We'll call this our date reviver, and this is a second property you can pass along, which essentially converts your value from something to something else. So, we can say function date reviver. This is going to take in a key, which we don't even care about. And then it's going to take in our value, which we don't know what the value is. So, we can say value of unknown. Just like that. And what I want to do is if my type of value is a string, which it should be because it's coming from the JSON parse. Oops, spell key properly. There we go. And we just want to use a fancy little regular expression here. I'm going to copy this over. Essentially, this regular expression is just checking for an ISO-formatted date, which is what happens when you take a date in JavaScript and convert it to JSON. It turns it into an ISO date. So, this is just saying, is this a date converted to a string? If so, I want to parse that as an ISO date, and I want to return that value as is. So, I'm converting my value to a date, or I'm just going to return my value as is, which could be a string, number, or whatever. There we go. Now, we can use that date reviver in all these places, and this will make sure to properly parse out all my date information, so everything works like we expect. So, if we just come in here, let's delete this, refresh our page, add a few different things, select a few values on these, and if I refresh my page, everything stays properly, which is exactly what I expect. Now, there is one thing about this use effect hook that I haven't covered yet because it's not important for this particular use case, but use effect also has a cleanup function applied to it. This is very useful for specific scenarios. So, I'm going to come in here and create a brand new use effect just for demonstration purposes. This use effect is going to be a use effect that is going to specifically maybe do something with our week offset related information. So, we're just going to say document. addEventListener, click. And whenever I click on this, I want to render out Whoops, I want to console log my week offset. There we go. Relatively straightforward. And again, I want this to only render a certain number of times. So, here I want to only render it when my week offset changes cuz that's the value I'm using here. So, now every single time my week offset changes, I reset up my event listener cuz otherwise it'll still use the old value. For example, here, I'm going to inspect my page. We look at the console. Just clear this out and we're going to click on the page. You can see it prints out zero cuz that's our current week offset. If I change this value, you can see it still prints out zero every time I click. And that's because I'm never re-running this code and it's always using the old value for my week offset. So, when my week offset changes, I need to rerun this code to add essentially a brand new event listener that has the correct week offset data. This will also not quite work like you expect, though. If I come into here and I just click on my page, you can see it prints out zero. That works just fine. If I go backwards a few times, you can see it is properly printing out the data of -3, but it's also printing out zero and -1 and -2. And as I go further, you can see it's printing out all of them. The reason for this is because I'm adding a new event listener every time this changes, but I'm never removing my old event listener. This is where the idea of cleanup inside of use effect comes in. So, here I can return a function and this function is used specifically to essentially unhook up all the things I did inside this effect. This function gets called every single time my use effect reruns. So, I call my use effect at this event listener. When I call it again to re-add this event listener, it'll call the code inside this return statement. So, let's just come in here. I'm going to create a function called handler. There we go. And inside here is where I'm going to call that console log code. And then I'm going to pass along my handler just like this. So, now I can come in here and say document .remove event listener for click. I can remove that handler. And now, essentially what this code is doing is it's saying every time my week offset changes, add a brand new event listener and remove the old event listener cuz this is only called when we try to recall this use effect. So, now my code will actually work like I expect it to. So, let's clear all this out. If I click and I make sure I refresh my page. There we go. You can see it's printing zero. If I go previous, you can see it's printing out only the number I want. When I click, you can see it prints out -6 every single time I click. If I go back a few times, clear this out, click, you can see now we're at -11. So, it's properly working just like I expect it to. Now, obviously there's much more to this use effect hook than I can talk about. I mean, in my course I literally have 10 videos just talking about the component life cycle and another six videos just talking about state. And then, I have a bunch more videos talking just about basic hooks. You can see here there's a 12 lessons just about some of the basic hooks and that's not even the advanced ones and other concepts in React. As you can see, it's a very, very large topic. So, if you want to dive super deep into learning all the advanced features inside of React, I highly recommend checking out my React Simplified course. Again, I'm currently running a sale on the course. It'll be linked down in the description if you want to get that. It's only available for this week though and then it will be expiring. Also, in this project we build or in this course we build up this massive project. It literally covers everything you would ever need to know about React. And if you enjoyed this kind of touch point of me talking about React in this one basic project, you're going to love what I talk about in the course cuz it's so much more in-depth with tons and tons of different projects and examples. But, if you're not ready to jump into a full course, maybe you want to learn just about the hooks in React. I have a completely free React Hooks Simplified course I'll also link in the description so you can kind of test out my teaching style on this free course before you dive into a paid course. With that said, thank you very much for watching and have a good day.
Original Description
React Simplified Course: https://learn.webdevsimplified.com/react-simplified/?utm_source=youtube&utm_medium=video-description&utm_term=video-id-9aTRnV6g0eQ&utm_campaign=react-promo-2026-05
FREE React Hooks Course: https://courses.webdevsimplified.com/react-hooks-simplified/?utm_source=youtube&utm_medium=video-description&utm_term=video-id-9aTRnV6g0eQ
Learning React is hard, especially if you are just getting started. In this video I will show you how to build out a full React application while also explaining every single important React concept you need to know.
📚 Materials/References:
GitHub Code: https://github.com/WebDevSimplified/react-habit-tracker}
React Simplified Course: https://learn.webdevsimplified.com/react-simplified/?utm_source=youtube&utm_medium=video-description&utm_term=video-id-9aTRnV6g0eQ&utm_campaign=react-promo-2026-05
FREE React Hooks Course: https://courses.webdevsimplified.com/react-hooks-simplified/?utm_source=youtube&utm_medium=video-description&utm_term=video-id-9aTRnV6g0eQ
🌎 Find Me Here:
My Blog: [https://blog.webdevsimplified.com](https://blog.webdevsimplified.com/)
My Courses: [https://courses.webdevsimplified.com](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:02 - Setup React
00:04:24 - Setup Tailwind
00:06:27 - Thinking in Components
00:08:15 - Custom Components
00:14:26 - Props
00:19:20 - Form Custom Component
00:22:40 - Habit List Custom Component
00:24:40 - Rendering Arrays
00:28:15 - Habit Item Component
00:37:00 - Advanced Props
00:47:55 - useState Hook
01:10:30 - Conditional Rendering
01:11:50 - useContext Hook
01:22:46 - Making UI Reactive
01:32:51 - Rules of Hooks Hooks
01:34:30 - Custom Hooks
01:37:18 - useEffect Hook
#TypeScript #WDS #ReactJS
More on: React
View skill →Related Reads
📰
📰
📰
📰
Frontend Dependency Injection: From Context API to Composition Root
Medium · JavaScript
A tabbed form that silently refused to submit — required fields hidden behind another tab
Dev.to · Susumu Takahashi
The DOM Isn’t Slow. The Way Most Code Talks to It Is.
Medium · Programming
The DOM Isn’t Slow. The Way Most Code Talks to It Is.
Medium · JavaScript
Chapters (18)
Introduction
1:02
Setup React
4:24
Setup Tailwind
6:27
Thinking in Components
8:15
Custom Components
14:26
Props
19:20
Form Custom Component
22:40
Habit List Custom Component
24:40
Rendering Arrays
28:15
Habit Item Component
37:00
Advanced Props
47:55
useState Hook
1:10:30
Conditional Rendering
1:11:50
useContext Hook
1:22:46
Making UI Reactive
1:32:51
Rules of Hooks Hooks
1:34:30
Custom Hooks
1:37:18
useEffect Hook
🎓
Tutor Explanation
DeepCamp AI