4.1 Writing a Stateful Component
We usually strive for stateless components—they are simply more efficient and much simpler to maintain. But there are times when a component needs state, and so I'll show you how to write a stateful component in this lesson.
1.Introduction1 lesson, 01:37
2.Hello, World2 lessons, 16:56
3.Bootstrap Button Group Component2 lessons, 20:48
4.A Digital Clock2 lessons, 20:41
5.A Multi-Selector Component1 lesson, 15:00
6.An Ajax-Powered Navbar2 lessons, 23:54
7.Conclusion1 lesson, 01:35
4.1 Writing a Stateful Component
Whenever we first start talking about writing custom components, I said that we can create a component in a couple of different ways. Now we've used just a normal function to create a component. But we can also use a class, and there's a few reasons why we would want to use a class as supposed to just a normal function. For one, it allows us to maintain state. So if we need a stateful component then a class is what we want to use. But it also allows us to tap into the life cycle of a component. There are certain things that will happen during a component's life cycle. And we can execute code in those different stages. It's kind of like whenever the document completely loads. There is a load event that we can tap into in order to execute code whenever the load event fires. It's the same type of thing, but they aren't really called events. And we will see that here in a few moments. So we are going to write a component called Clock. And it is somewhat based upon the Clock component that you would find in the React documentation. If you go through the tutorial, you will see that they walk you through the creation of a Clock component. And this is somewhat similar. So I've written a class. I used the class keyword, I called it Clock. And we want to extend a class called React.Component. That's very important because we need to extend that component in order to have a component. And the first thing we need to do is write a method called render. Now the render method is very similar to just the normal function that we wrote a couple of lessons ago. This is going to render our component. So if you wanted to convert a stateless component, which is one that's written with just a normal function, into a stateful, you could take the contents of that function and then put it inside of the render method. Now, you will of course need to massage you code however you need to, but that's a good first step. So since this is going to be a Clock, we're going to be displaying the time. So lets go ahead and do that here inside of the render method. Let's go ahead and get the date. We will new-up the date constructor. And then we are simply going to return some jsx. We're going to use a p element and we are going to say date. We're going to use the LocalTimeString. And that's going to be it. But let's also add some custom CSS. Because if we view this in a browser, the text is going to be small, and it's also going to be up here in the top left hand corner. So we can add some padding and some margin to the body. So let's go ahead and do that, we'll say body. And we want padding, 10 pixels will be fine. Let's add a margin with 10 pixels. And let's also increase the font size, so let's do 3.25em. That should be large enough. And let's close out that style element. So let's refresh just to make sure that this looks okay, and it does. So my current time is 10:07 PM. And we of course want this to update every second. So we are eventually going to set our component to maintain the state, which is going to be the current time. And it's going to automatically update. So we are rendering that. The next thing that we want to do is store our state. So we want to, first of all, have a constructor. Because eventually we're going to pass props to our Clock component. And we also want to go ahead and initialize our state whenever our Clock component is created. So the first thing that we need to do inside of our constructor is called super. We're going to pass the props so that everything gets initialized as it needs to. And then we're going to set our state. Now we have a very special property called state. Anything you put inside of this object is considered the state. So we are going to assign this as an object. We're going to have a property called state. And we can go ahead and initialize that as a new date. So we have now set our state. And inside of our render method, instead of newing-up date, we can say that this.state and then date. And then we can use that value inside of our components. Now, we aren't updating anything. So we are still just going to see the time as to when our application runs. But it at least is working. So now we want to work on making this update. And to do that, we need to modify our state. Because any time that our state changes, the render method is going to execute. So if we change our state every second, then we don't have to worry about any dumb code for updating what is rendered within the page. React is going to do that automatically for us. So let's write a method called tick, because our clock ticks. And we will eventually set this up to tick every second. So inside of our tick method, we want to change our state. Well our state is our date. And we have a method called set state. Whenever you call set state and you change the state of your component, then that's going to kick off the whole rendering process. So we're going to say date and then we're going to new-up date again so that whenever the tick method executes, it's going to update our state. Which is then going to invalidate what is currently rendered within the page. And then React will re-render our component. Now, we haven't set up tick to execute yet, we just have that method. So we need to know when to start ticking our clock. And the best place to do that is whenever our component has been loaded for the first time in the page. And loaded really isn't the right term. Whenever the component is rendered, that is the term that we want to use. And we know when that happens because our component has a method called componentDidMount. This is essentially the on load event. So whenever our component is rendered in the page, then this component DidMount method is going execute. And here we want to call our tick method, but we want to do so on every second. So we're going to set an interval. And for each second, we want to call the tick method. So we will simply say this.tick, I'm using an arrow function here. And we want this to tick every second. So we aren't kicking off the interval in the constructor. We don't want to do that. Instead we want to do that whenever our component has been rendered in the document. So that's when the component DidMount method is going to execute. That's going to kick off the individual ticks. And then we will see our component automatically update. So there we go. Well let's add a prop that will allow us to set an offset in hours. Now this isn't the time zone, this is actually just changing the time of the clock so that the time zone is still going to be whatever the current date is on the machine that this is running on. The clock is just going to be an hour behind, or an hour ahead, or whatever the offset is going to be. So in this particular case, we are going to set an hour offset of 1. And then we just need to reference that prop inside of our render method. Because whenever we render our date, we have retrieved it from our state so that we can then modify it. And we aren't modifying our state, by the way. We are going to modify that date value and then display it. So it's purely for changing what is going to be displayed, as opposed to updating the state. So first of all, let's change this var to let. We need to get in the habit of doing that. And then we will say let and we'll go ahead and retrieve our offset. So we will say, hourOffset =. Now, we are passing in a numeric value here. But somebody could pass in a string. Or it would be nice if we could not specify an hour offset at all. And that would just display the current time. So we need to take all of those things into account. So we're going to parse, and we are going to say this.props.hourOffset. But in the case that this is undefined, we just want an offset of 0. So we're going to say 0. That's really not necessary in this case because this is a integer value, but this is going to be fine. Okay, so we have our date from our state. We have our offset. If it is set, then we are parsing that into an integer. If not, then it's just going to be 0. And then we just need to modify our date. So we will call the setHours method. We want to get the current hours. And then we want to add our offset so that whenever the date is displayed, then it is going to display with the offset value. So, if we go to the webpage, let's refresh the page. And we are back an hour. And just to prove that, we can have two clocks here. So, let's add a div element. We'll have a Clock with just our current time. Then we will have one with an offset of -1. And then we will see what this says in the browser. Our first clock will be 10:32, and then the offset will be 9:32. And I should also mention that the state that we are seeing is independent for each component. So the date that is in state for our first clock is completely independent from the state in our second clock. And we could prove that by changing the date that we store in our state. So let's quickly do that, let's write a method called getOffsetDate. And we are essentially going to do what we did here. We're going to retrieve this state, or rather, let's not get to this state. Here we are going to do this. We will just new Date here, we will get our offset. Then we will set our new hours, and then we will return date. So that now whenever we initialize our state, we are going to call this.getOffsetDate. And whenever we update our state inside of the tick method, we are going to call this.getOffsetDate. So now, whenever we render this we could just say this.state.date. And let's go to the browser, let's refresh. And we see the same results as we did before. But now it is absolutely apparent that both of these Clock components have their own unique state. Because the date that is stored in the state now takes the offset into account. So we have a stateful component and all is well and good in the world, but let's add some flexibility. Because we might want to display different things about the date. Not just the time, but maybe we want to include the date as well, or maybe we just want to display the date. And that is where higher ordered components come into play. And we will look at that in the next lesson.