1.2 Thinking in React: Component Lifecycle Methods
In this lesson, I’ll show you how to implement a simple timer component that uses many of the React lifecycle methods. You’ll see how to respond to mount and unmount events, handle resources, and respond to changing props.
For more information about React’s lifecycle methods, check out the links below.
1.Thinking in React: Component Lifecycle Methods2 lessons, 09:44
1.2 Thinking in React: Component Lifecycle Methods
[MUSIC] Hi I'm Andrew Burgess. Let's talk about the React lifecycle methods. If you've used React before, you've obviously created components in React. And you may have also heard of the React lifecycle methods. These are various methods that are executed at specific points in a component's lifecycle. So when you create a React component, it has a process of being created, eventually updating as it is displayed on the page, and eventually being removed from the page. And this is called the React lifecycle. So let's take a quick look at the seven different React lifecycle methods. I've got them listed here in the order that they would occur but we're not gonna look at them in that order. Let's start with componentDidMount. The component DidMount method is invoked only once. And as you can probably guess that is right after the component initially mounts. This method is a great place to add event listeners, perform Ajax requests, mutate the DOM, anything that you need to do after the component is displayed on the screen. We have a basic Timer component here. Let's give it a componentDidMount method. So we can say componentDidMount and I should mention, it's this easy to use these React lifecycle methods. You just add a method with the right name to your class. And what we're going to do is set an interval. So we'll say setInterval and this function will be called once every second. And it's going to do something very basic. We will just increment a second count. Now we don't have an initial state, so let's just add a getInitialState function here. And in this function, we'll just return an object with a seconds count that starts at 0. And then, in here, we can say this.setState and we will set seconds equal to this.state.seconds + 1. Now inside our component here let's go ahead and display this.state.seconds. And now when we run this, you can see that we have the seconds counting over here in our output display. Now before componentDidMount, we have componentWillMount. This is also invoked only once, but it happens immediately before the initial rendering of the component. In here, we can call setState and our state will be updated before the component is mounted and it's not actually gonna cause an extra render. So let's create a second component here. And we will call this MinuteCounter. And in the render method for this, we're just going to render this.state.minutes. Now, we're gonna render MinuteCounter from inside of our Timer here. So let's go ahead and say Timer returns a MinuteCounter object and we will pass it seconds, which is just this.state.seconds. MinuteCounter needs to receive that prop and convert it to the minutes value. So, what we can do here is say, componentWillMount, and remember this will happen once before MinuteCounter is rendered. And in here, we can just create a minutes value. And what we'll say is Math.floor around down. And then we can say this.props.seconds/60. And then underneath that, we'll say this.setState, and we can just set a minute's property. Okay, so now if we go ahead and run this, we should see 0 minutes. Now you would expect that after 60 seconds, this would get updated. But that actually won't happen. And if you think about it, you'll remember, why, componentWillMount is only invoked once, when the MinuteCounter is being initialized. If we changed the second count in our Timer here to 120 at the beginning, and rerun this, you can see that we'll start at 2 minutes, but again, it's never going to go up. What we need to use to update this state is componentWillReceiveProps. And notice that it receives the nextProps as the first parameter. So in MinuteCounter here, let's add a function called componentWillReceiveProps. As you might expect, componentWillReceiveProps is invoked whenever a component receives new properties. This method is not called for the initial render. And what we can do is update existing props or even setState in here. And if we do call setState, it won't cause an extra render. So what I'm gonna do is copy these two lines from up here, and paste them down below. And then let's change our call to this.props to instead be nextProps. And this will update our minute count every time our seconds are updated. So let's bring this down to only 100 milliseconds. And now if we run this, we should see that after just a couple of seconds, our count goes from 0 minutes up to 1 minute. And so you can see that now because we're using componentWillReceiveProps, we are continually updating our minute count. Now I've added a seconds state value to our MinuteCounter. And we can see that because of componentWillReceiveProps, we are updating our component every second. But let's say, we didn't want to update every single second, we want it to update it in larger increments. For this, we can use the state method shouldComponentUpdate. The shouldComponentUpdate function takes the next properties and the nextState, and it returns a boolean, answering the question should we re-render the component. If we return true, the component will be re-rendered. So let's say, we only want to re-render every five seconds. What we can do then is just return nextProps.seconds, use the mod operator, divide that by 5, and see if that equals 0. So that means, if we rerun this, this will only update in 5 second increments. The next method is componentWillUpdate. Now componentWillUpdate is invoked immediately before rendering, whenever new props or new states are being received. This method is not called before the very first render. It's only called before subsequent renders, and we can't use componentWillUpdate to change the state. ComponentWillUpdate is useful if you wanna send events out of your component to other places. And it's good for other things too but let me show you how we might use it in that regard. Let's say that our Timer here wants to know whenever the MinuteCounter reaches the beginning of a new minute. So we add a second property here to the MinuteCounter, onNewMinute. And this is a simple example of an event that our parent component wants to know about. It's just take a minute count here, and we can just console.log starting minute, minute count. So now, what we can do up here in our MinuteCounter is add a componentWillUpdate method. And what we can do in here is say, if nextState.seconds == 0. And remember nextState is being set here in componentWillReceiveProps, where we're updating the state, right? So if the second count is 0, that means we're just starting a new minute. So if that's the case, we can say this.props.OnNewMinute. And we can call that function and we can pass it nextState.minutes. Now let me pop open the console for this. And if I rerun our little program here, you can see that as soon as we hit the first minute, you can see it says starting minute 1. And maybe this count is wrong, maybe I should really say starting minute 2. But you get the idea how we can use componentWillUpdate to trigger events throughout our application. The second last method is componentDidUpdate. ComponentDidUpdate is invoked immediately after the component updates and the DOM has been re-rendered. This is not called after the initial render but after any subsequent renders. The documentation says you could use this as an opportunity to operate on the DOM whenever the component hasn't been updated. If there's something you need to do that you couldn't do in your render method, this would be the place to do it because our component has been freshly rendered. But instead of looking at an example of that, let's jump to the very last one, which is componentWillUnmount. I'm going to paste in another component here, and this is just very simply a Toggle component. It has a state of on, and we can use this button to toggle between having a Timer and not having a Timer. So I'm just going to go ahead and render our Toggle here. And let me go ahead and click Run. And as you can see, initially, our toggle button is off. But if I go ahead and click toggle, you can see that our counter begins. If I click toggle again, the toggle turns off, but notice we get these warnings down here, that setState is occurring, but it can only update on a mounted or mounting component. And what's happening here of course is in Timer here, our setInterval is continuing to run. So what we need to do is turn off our setInterval. Here in the Timer, let's set a property this.intervalId, and now let's have our final React lifecycle method componentWillUnmount. This will be called right before the component is taken off the screen. And all we need to do in here is say clearInterval(this.intervalId). Excellent, so now let's rerun this. I will clear the errors from the console here. We can toggle it on, toggle it off, and now notice, we get no errors because our interval was cleared and our component is not trying to update itself. So, of course, you can use componentWillUnmount to clear intervals. But of course it's also useful to unhook event handlers. So there you go, that's a quick look at the seven React component lifecycle methods.