- Read Tutorial
- Watch Guide Video
And so that's what the goal of this guide and then the screencast is going to be, is I want to simply take all of the magic out of the process so that you can understand it. And by the end of it hopefully, you'll see that these methods are even pretty intuitive and you'll see how you can use them in your own projects.
Now before we dive into the code and we walk through each one of the lifecycle methods what I want to do is I want to take a step back and I want to draw a real-world analogy for the way that component lifecycle methods made sense to me. And in order to do that we are going to take a drive to a fast food spot. Now you can pick out your favorite, I'm going to go with "In n Out". Anyone watching internationally may not know it. It's a delicious burger joint that I go to whenever I'm in a city that has it.
We're going to use this trip to help have a high-level understanding of how these lifecycle methods work. So we're going to go to the drive-thru. But before we do that we first have to drive up to the restaurant as we do that. If you're anything like me you start trying to make up your mind on the kind of things that you're going to want to order.
Well in react's world that is called the Mounting process
. So what we're doing during the mounting process is we're picking out what kinds of data and processes need to occur when that component is going to load. So if it is some kind of page content type of component and we're getting data from some outside API then we need to implement all the processes that will occur so that when someone navigates to that component then we're putting the right steps in place so that the page will have content. That's the mounting process and it's that first stage kind of like when we're going to the drive-thru and we're starting to pick out what we want to order.
So moving right along, we've pulled up to the drive-thru order window and we've placed our order, and that's all part of the mounting process. When we take in relation to react, so that's kind of like us going to a page and having the page load. Now, what happens if the voice coming at the other end says something like "Oh, that is not available today. You need to order something else." Well, we can change our minds and then we can give another order or we could update our order. Well, that is also a lifecycle method in react.
So each time that you have a component that gets updated. So that could be as simple as someone typing into a form component or it could be something even more advanced like a WebSocket where you're getting live stream data into your application every time that happens a number of other lifecycle methods occur.
So you have access at each stage of that lifecycle. So from the very beginning before the page and that component have even loaded all the way through to when you might need to make some live changes and it also comes into play with how react is so good at performance because during that update process even though you have access to all of the various workflows that are occurring when something has been updated react is very good at being able to tell the difference so in other words if you have a big page component and only one part needs to update.
So if you have eight components on a page and only one of those needs to update in that lifecycle method only one component will need to be updated, so all the other ones remain the same. That's part of the reason why react if implemented properly has very solid performance.
So we're almost done with the entire lifecycle. We have gone from the very beginning before we pulled up we decided what we wanted to order. We updated our order when we found out that they had some changes on the menu and then we drive up and we pay, and then we receive our food, and then we drive away. Well, that is called The Unmounting process
so as you drive away there are a number of things that you do.
You start to put the car in drive, you move forward, you make sure no one is in front of you, and then you leave the restaurant kind of like with some type of component in react, whenever you don't need that component anymore you have access to that leaving process that unmounting process and the example that we're going to work through is going to mimic a type of chat bot so it's going to be a system where you could have all kinds of discussions and chats that are occurring and you may have hundreds or thousands of them occurring at one time.
If the individual leaves that page so they want to navigate somewhere else in the application you don't want that component going in the background, that'd be very very bad from a performance perspective. So when they leave or when the component is unmounted then you can do some cleanup tasks.
So we've started the very beginning which is the mounting process. We've updated and then we've unmounted and inside of each one of those categories is a full set of methods that you have access to. And we're going to walk to every single one of them and hopefully, by the very end of it you'll be able to see that really all these methods do is they give you access to perform whatever task you need at whatever stage of the user's experience with your component. And we're also going to talk about a few other concepts in order to implement this properly. We're going to implement routing in our system along with a few other fun projects.
So now that we have the high-level view and some analogies on what lifecycle methods are let's dive into the code.
Now, that you have a high-level overview of the basic flow of the component lifecycle inside of react. Let's actually dive into the code and see exactly how it works. Now I have this completed project right here and it's on github I'll put it in the show notes so that you can view the code and I also inside the readme added quite a bit of content. So I added the topics that were going to cover such as making sure we cover the react router dom. We're going to talk a little bit more about class versus functional components, object deconstruction, and then most importantly we're gonna spend most of our time talking about the component lifecycle methods.
I also copied the documentation, so if you come to the react docs then right here you'll see it has the full lifecycle set of methods. But this is a little bit confusing because imagine that you just copied each one of these lifecycle methods into a project into a component you'd actually get a number of errors because several of these as you can kind of see are marked as being unsafe. And so I put all of those inside of the dock. But then what I did is inside of one of the components I cleaned it up and I only use the components that you are actually going to want to use.
So hopefully that can kind of help streamline the way you think about them a little bit more. So if you click on this workflow component I put in the methods that you actually want to use. And I also placed in the order that they're called in the comments. And so once we build our project I'm just going to copy this whole file over and then we're going to walk through the order that everything is called in.
So let's start by building the project. And if you've never gone through one of my deep dives before I always use the devcamp-js-builder so I'll include this in the show notes as well where you can install this globally and then you can run js-generate
to build out a project. So I'm going to switch over to the terminal and just say js-generate
and I want to pick out the react skeleton project here
and the name I'm going to give this is going to be DeepDiveLifecycle
so it's going to generate that for me. And now I'm going to cd into it and then run npm install
. Fast forward it as all of the dependencies are installed and then I'll come back when it is live, okay we're back and it looked like everything installed properly.
So I'm going to run npm start
and I'm gonna keep the server running in the background so we can come to the browser go to localhost: 8080
and we can see that that is running properly.
Now I'm going to come into visual studio code go file open folder
and then just click on that entire folder and open it up
and we will have our project right here.
This deep dive is going to have two components and I don't mean react components. It's going to have two types of projects that we're gonna work through, We are gonna put them all in one codebase. But I want to start off by showing you what we discussed already with being able to see the timing on when all of this occurs.
So I want to be able to have this workflow where we can see when the constructor is called, when getDerivedStateFromProps is called, all of those things so we're going to incorporate all of this but we do this a little bit later because I want to show you how you can do it when you are navigating from page to page. So the first thing that we're going to do is we're actually going to implement a little bit of functionality so we're going to build out a few other components and we're going to mimic a chat type system. So we're going to see how we can build that out. We're going to add in those components and then from there, we'll eventually get to where we can see literally like in the console we're going to be able to see when each one of those lifecycle methods is called.
And in order to really be able to see this, this is the reason why I want to install the router so that we could see, we're going to have multiple components on the page and we're going to click. So what we'll be able to see is if you come here to our localhost we'll have 3 links eventually and when you click on one it will act like it's routing so it will go and it will only show that component and it will hide the other ones. The reason why I wanted to incorporate that in this particular deep dive is because that shows you how you can hit a few of those other lifecycle methods.
So, for example, the unmounting process the best way of being able to mimic that is by using routing because you do want to leave one of the components and go to the other one so you want to unmount one. And so that's why I want to include routing into it so that we can see exactly that entire process.
Now I'm also going to open up the dev tools here and I'll open up the React tools. So make sure that you have these installed and this is just the react extension that is provided by Facebook, so I definitely recommend that you have this installed on the system. And now let's go into our package.json file and we're going to install the react router Dom library. So let's say react-router-dom
and I'm going to use 4.2.2 so that's a version we're going to use.
And I'll hit save, now in case you're going through this guide and it's been a long time so maybe it's been even a couple of years or something like that. Then you can just go to the NPM registry here and type react-router- dom and then as you can see I'm using the latest version.
So you can see whatever the latest version is for you right here. And then you can use that inside of your package.json file. So after you've done that come to the server, stop it, run npm install, it'll install the new library the react router dom library for us. It'll add it to the node modules and then we will be able to use it. So it's now run npm start and assuming we don't have the issues with that installation it looks like everything worked properly. So yes everything is back and obviously, we don't have any routes or anything yet that is what we are going to add now.
So let's start by going into the src directory then components and let's add these new files.
So I'm going to create one that's called discussion.js
an inside of it I'm going to just have a basic react class component here and I'm going to call it Discussion and for right now let me just put some text here, so I'll say div discussion that's the first one.
discussion.js
import React, { Component } from "react"; export default class Discussion extends Component { render () { return <div>Discussion...</div>; } }
And then we want to have one called rules.js
and it's only real purpose is going to give us the ability to have another component that we can click on and we can mount and unmount some of the other ones. So here I'll say rc
and this one is going to be a rules component and this one's just going to say rules
rules.js
import React, { Component } from "react"; export default class Rules extends Component { render () { return <div>Rules...</div>; } }
and then we're going to build one more component which is going to be that lifecycle workflow one that I'm just going to call workflow.js
and same thing. So rc and then this is going to be just workflow.
workflow.js
import React, { Component } from "react"; export default class Workflow extends Component { render () { return <div></div>; } }
Now, once again if you notice how I only have to type rc that's not something that you will have by default on your system that is in your vs code user snippets and I have a video on that if you are curious about it and so you can just simply go into your preferences and then into user snippets and so you can come down to preferences user snippets just like this.
And then I believe I have mine in javascript.json
.
And yes I do.
So this is if you'd want to pause the video right now and copy this all into your own user snippets
javascript.json
"Skeleton React Component": { "prefix": "rc", "body": [ "Import React, { component } from 'react';", "", "export default class $1 extends Component {", " render() {", " return (", " <div>", " $2", " </div>", " );", " }", "}" ], "description": "Generates a basic React Component" }
so I have what's called the skeleton react component here prefix rc, body, and then description. So that is what allows me to just type rc and then it automatically fills all this in for me and then it places my cursor right here($1)
so I can type in the name of the component and once again you can go through the video that I have on that, if that is something that you're interested in.
Now, inside of the workflow let's also put in that heading so I'm going to just say workflow close off that h1.
workflow.js
import React, { Component } from "react"; export default class Workflow extends Component { render () { return <h1>Workflow...</h1>; } }
So now we have our three components but technically none of them are being called right now so let's just make sure that they're all working so we can come to app.js
and let's just call each one of the components so I can call discussion here, this is also just good practice for being able to repetitively create components and then call them from other files. So we have discussion rules and then workflow. And those aren't going to work quite yet because we first need to import them. So we'll import discussion from ./discussion and then let's just copy this a few times, and then we're going to have rules and then we're going to have workflow.
app.js
import React, { Component } from "react"; import Discussion from './discussion'; import Rules from './rules'; import Workflow from './workflow'; export default class App extends Component { render () { return ( <div> <h1>DevCamp React Starter</h1> <Discussion /> <Rules /> <Workflow /> </div> ); } }
Let's just make sure that that's all popping up on the screen. So if I come over here. There we go, we see discussion rules and workflow.
And the reason why workflow is bigger is because I threw that into an H1. But none of it matters were going to actually convert them into links for our router next, but this just shows that we've created the components and we can call them properly, so that's a good first start.
Now if you've never implemented the router before there are a few steps that we need to take. The first is we're actually going to traverse all the way up to our entry point here. So this is going to be in index.js
this is outside the components directory, it's just going to be at src and then the index.js
file.
And what we need to do is we actually need to wrap our app component inside of a browser router. So if we come up here right below where we have ReactDOM we also need to import the routers so that this file has access to it. So I'm gonna import browser router which is provided from react router Dom I need to import the route and then the link from react-router-Dom, just like this.
index.js
import React from 'react'; import ReactDOM from 'react-dom'; import { BrowserRouter, Route, Link } from 'react-router-dom'; import App from './components/app'; ReactDOM.render( <App /> document.querySelector('.app-wrapper'));
And now inside of here, I need to call that component. So this is a component that we didn't build, this is a component provided to us from react-router-Dom if you went through their source code you'd be able to see that they have a component just like we're creating our own components just like this. So we have our BrowserRouter component and this one we're actually going to wrap the app inside of. So this is how we're able to call this effectively inside of the file and have links, and when you click on one of the links it will go and show one component and hide the other component.
index.js
import React from "react"; import ReactDOM from "react-dom"; import { BrowserRouter, Route, Link } from "react-router-dom"; import App from "./components/app"; ReactDOM.render( <BrowserRouter> <App /> </BrowserRouter>, document.querySelector(".app-wrapper") );
So technically you could build all this kind of functionality yourselves. And I have gone through a really fun workshop from the creator of react-router-dom and he showed how we could build it ourselves. But I have found that it's actually much more intuitive and much faster to just use the tool because it's very lightweight and works quite well. So that's the first part that is what we need to do by wrapping the entire system up in the router component.
So now that we have that, now we can start building out a navigation component. So as you may have guessed we're going to go into the components directory and create a new file this will be called navigation.js
. And inside of here I'm going to I'm not going to build out the full component so I'm going to simply use this as a functional component so I'm gonna say import React from react and then I need to import the NavLink from react router dom so I'm gonna say import NavLink from react-router-dom just like this.
navigation.js
import React from 'react'; import { NavLink } from 'react-router-dom';
And now we're going to create our functional components, so I can just say export default function and here inside of it I just want to return some jsx code. So this is going to be where we have all of our links. So let's wrap all of this up into a div and then inside of here. I'm going to have a number of links so each one of them is going to be wrapped up in their own div and then once we have our first one we can really copy and paste it for the other ones.
So let's call a nav link component. This is provided by react-router-dom and then it also takes some props. So I'm going to say exact and we don't have to pass anything to exact if we just say the word exact it's going to know what we mean here. And this is going to be for our root route. So it takes props of to and so I'm going to say to just slash which means that if you go to a local host 8080 or whatever the url your application is the home page is going to be using this route. That's how you can declare a home page with react-router-dom and I want the home page here to be our discussion component and then this is going to be closing off that NavLink and then that is all we need for the first one.
navigation.js
import React from "react"; import { NavLink } from "react-router-dom"; export default function() { return ( <div> <div> <NavLink exact to="/"> Discussion </NavLink> </div> </div> ); }
So now we can just copy this for the other links. So we're going to have a discussion and this next one is not going to be exact. This one is going to be pointed to we can just say rules. So here you can just slash rules change the text that you want to appear and then we just have one more. This is going to be for our workflow.
navigation.js
import React from "react"; import { NavLink } from "react-router-dom"; export default function() { return ( <div> <div> <NavLink exact to="/"> Discussion </NavLink> </div> <div> <NavLink to="/rules"> Rules </NavLink> </div> <div> <NavLink to="/workflow"> Workflow </NavLink> </div> </div> ); }
And one thing I want to note here if you're not that familiar with using react-router-dom pretty much everything that we have here is completely up to us in how we want to name it. So that is something that I just want to be very clear with. So when I say NavLink to workflow this could be workflow-asdf it really doesn't matter, it can be whatever you want it to be. We're simply defining what we want those routes to be right here and then we're going to be able to wire this up inside of another component so we'll call these. So when you click on one of these links it'll redirect to the other component.
And now having said that let's actually go build that component. So I'm going to come in here create one called page-content.js
and now we're going to create another functional component. So this is not going to be a class one. So I'm just going to import React by itself from react and then we're also going to be working with another library with the react-router-dom so I want to import with the curly braces switch and then route and this is from react-router-dom. Then I want to import each one of these components we created here so we're no longer going to be calling them from app.js but we are going to be importing them directly into the page content. So let's come over here and I'm just going to paste those three in and that's all we need to do for our imports and now let's create our functional component.
So I'll say export default function and you may notice I'm not using an arrow function for these default functions and I'm also not giving them a name and it's because whenever you say export default function what react does here is it assumes that you are wanting to create a functional component and then it's going to look at the filename here and then when you import one of those files you can call it whatever you want and it's going to simply wrap up this function here and it's going to treat it like a functional component. So you can as long as you import the correct file name then you're going to be able to use this.
So in the last deep dive, I showed you a little bit of a different approach. And it's mainly because I want you to be able to see all of the different options that are out there because as you're reading tutorials as you're going through documentation you're going to see variations of how you can do things. And so I want you to be able to see all those options so that you can pick out which one you prefer.
So now with all that being said let's now return and let's add some jsx so I'm going to add a div let's close it off. And now inside of here, I want to implement what is called a switch statement, so I'm gonna say switch, and this is not switch like from the programming language perspective. This is something that is provided to us from as you can see up here react-router-Dom.
So now with that let's go and let's build out these routes so I'm going to call the route component and we're going to call it exact on each one of these because I want it to match the path exactly, and so when I say route exact path equals the root route and then I want the component to be discussion. So now we have route exact path. And then we want rules, this is going to call the component of rules and then lastly we have workflow and this is going to call the component workflow.
page-content.js
import React from "react"; import { Switch, Route } from "react-router-dom"; import Discussion from "./discussion"; import Rules from "./rules"; import Workflow from "./workflow"; export default function() { return ( <div> <Switch> <Route exact path="/" component={Discussion} /> <Route exact path="/rules" component={Rules} /> <Route exact path="/workflow" component={Workflow} /> </Switch> </div> ); }
Okay, so I know that was a lot of typing and a lot of setup but we pretty much have everything we need now in order to have a fully functional app with routes and multiple components. I know we haven't really gotten to the main point of this which is the component lifecycle. But this is really necessary because the lifecycle isn't really that important until you get to the point where you're working with multiple components because the entire point of the lifecycle is that you can work with a component at different stages of it and if you only have one component you really for the most part usually only have one stage.
So if you have multiples though you're going to be able to see how this can work. So now let's go into our app and now all we have to do is import the navigation component and then that page content 1. So here I can say navigation and then we have our page contents and then we can import them from up here. So import navigation from this is just going to be ./navigation and then the page contents from page-content.
app.js
import React, { Component } from "react"; import Navigation from "./navigation"; import PageContent from "./page-content"; export default class App extends Component { render() { return ( <div> <h1>DevCamp React Starter</h1> <Navigation /> <PageContent /> </div> ); } }
So that's usually a little bit more work than I'd like to do without testing at all in the browser. So let's go and see if we have any typos or anything like that. And it appears like this is working so you can see we have discussion loading up automatically, so right here if I click on rules that's working perfectly, workflow's working perfectly. So this is perfect, I like it.
So you now know how to implement routing here if you didn't already know how to do that. And then also work with multiple components so now that we have all of this we are finally ready to see how the component lifecycle works. So let's come to discussion make sure it starts right there. And now let's come to this workflow file now you would not want to watch me type out all of this I promise you that. So let's come over here and let's copy all of this. Copy all of that here. And let's come down into our workflow file. I'm going to just select everything and in our workflow get rid of it, and then let me just paste everything from that file area. OK.
import React, { Component } from "react"; export default class Workflow extends Component { // First constructor() { super(); this.state = {}; console.log("constructor"); } // Second static getDerivedStateFromProps() { console.log("getDerivedStateFromProps"); } // Fourth componentDidMount() { console.log("componentDidMount"); } // Fith (after update) shouldComponentUpdate() { console.log("shouldComponentUpdate"); return true; } // Seventh (after update) getSnapshotBeforeUpdate() { console.log("getSnapshotBeforeUpdate"); return true; } // Eighth (after update) componentDidUpdate() { console.log("componentDidUpdate"); } // Last componentWillUnmount() { console.log("componentWillUnmount"); } handleClick = () => { console.log("button clicked"); this.setState({ pageTitle: "Workflow" }); }; handleKeyUp = e => { this.setState({ inputDetails: e.target.value }); }; // Third // Sixth (after update) render() { console.log("render"); return ( <div> <h1>Workflow</h1> <input type="text" onKeyUp={e => this.handleKeyUp(e)} /> <button onClick={this.handleClick}>Click Me</button> </div> ); } }
So now we have everything here and this isn't going to do a lot from a functionality perspective. But instead what we're going to do is we're gonna open up the console and we're going to see the order that each one of these lifecycle methods is called. So that's really the first stage I think in understanding the lifecycle method and that entire process is seeing the order in which they're all called.
So let's come back to our localhost and click on the console. Now I want you to see that each one of the lifecycle methods I placed a console log statement there so that you'll be able to see the exact order that they're called. So now if I click on workflow here then you're going to see that's that's fine, this is just a warning.
But before you get into there look at this, the very first item that's called is constructor. So that is number 1 and if you come back and look I added comments that you could see each one of these.
So the constructor is called the very first time and so it's that state and then you can see that I'm just printing out that this is when the constructor is called. Now the next one that's called is getDerivedStateFromProps and you get this little warning but don't worry it's just telling you that a valid state object or noll must be returned and right now because everything's pretty much hardcoded in there then that's why it's doing it. If we wanted to add let's say inside of our state object we wanted to maybe add a page title or something like that. So I could say pageTitle: "Workflow" and hit save here.
Now let's clear our console and then if I click on rules and then click on workflow you can see that that's now gone because now it actually is getting props so if you notice before there were no props because we weren't passing a props to it you wouldn't usually, and it brings up a good point. You're not going to use getDerivedStateFromProps unless you're actually passing props around.
So that's it's good to know when it's used but it's also good to know the little warning and what kinds of errors you can get if you're working with components that aren't working with props. So you may notice we kind of went back in time because the component unmounted. So when we left it when we left the workflow and went to the rules page then it unmounted so it already showed that, then it called the constructor.
Now, this is really important, this is one of the things I've seen that can kind of trip up some people who are trying to learn react. They think that componentDidMount
is where they should place their state. So if you are wanting to set state, like we have state with this page title.
They think "OK, I can set the state in the spot where componentDidMount is". But as you can see this actually gets called fourth. So there are three other things that happen before this is going to fire. So if you try to place this state right here and let's just do it, you shouldn't believe me you should actually test things out. So if you go and let's get rid of state here. So if we get rid of this and come down into the component did mount and let's try this let's try calling page title and we'll add our workflow here.
Now if we come down to the very bottom. So if I come down here and let's say that I just want to put this on the screen. So I just want to say something like I want to have a paragraph tag and say this.state.pageTitle
. If you're watching this, raise your hand if you think that this is going to work. Because technically you might think if you listened to the name componentDidMount you may think that that would work and that that would be a good spot to put your state call but you can see we have a whole error and this error is actually quite descriptive especially for react.
It says there is a typeError we cannot read property pageTitle of null. And the reason for this is that when the component is called when it is loading, we have our first call here which is a constructor. This is what happens at the very first time, the next one is getDerivedStateFromPromps which you are only going to need when you are trying to pull in props, right now we're not trying to do that.
Then the third call is to render. Now this is really important because what this means is that render happens before the mounting process happens so if you have anything that you're calling inside of render you need to make sure that it is in either the constructor or if it's props you're bringing in and it's in the getDerivedStateFromPromps, so that is something that is very important. Let's come down here and let's fix our errors so I'll put our state back into its current working order and we are all good.
Now if I click on rules you can see it unmounts go back to workflow and everything is working.
Now you may notice that so far I've only talked about the mounting process and inside of that grouping we have the Constructor, we have getDerivedStateFromPromps, we have render, and then we have componentDidMount
. So that's good, but those are only four of them. And as you may have noticed we have eight of them or nine if you include component will unmount. So what all of these do is they all speak to the update process.
So the update is something that's very important because typically when you're building out dynamic applications you expect there to be an update at some point or another. So here we have all kinds of different update processes. And I want to walk through how they work because it's important to understand exactly what updating really means. So if I have some inputs and some buttons here and I want to show you a couple things.
So first let's take a look at this button, I have the full finished version of it here
workflow.js lines 57-65
return ( <div> <h1>Workflow</h1> <input type="text" onKeyUp={e => this.handleKeyUp(e)} /> <button onClick={this.handleClick}>Click Me</button> </div> );
Where I have button with an onClick method and then it calls this handleClick function right here and then that's it, it just says click me. And inside the handleClick, I have a console log statement and then I'm setting state.
workflow.js lines 43-46
handleClick = () => { console.log("button clicked"); this.setState({ pageTitle: "Workflow" }); };
Now let me comment out setState here and switch back. And so what is going to happen now, I'll clear our console out. If I press click me you can see it says button clicked.
But as you may have noticed even though it says button clicked it doesn't actually call any of these update functions, and that is critical to understand. When it comes to the updating process React is very efficient. And so what it is going to do is it is only going to call these update methods. If the component itself in its state has changed. So as you saw none of those got fired, but now if I uncomment that and now we have set state back in place, now watch what happened. So clear the console out now if I press click me, now we have all those methods.
So we have button clicked
which we had before then we have shouldComponentUpdate
then we have render
once again which is important to keep note of, then we have getSnapshotBeforeUpdate
and then we have componentDidUpdate
which is kind of like component did mount. This is like the updated version it is after the entire process has occurred. It's rendered on the page this is kind of like the final State of the update process.
But this is the full order of them and so this is something that is very important to know. It's also important to realize that render is called in both the mounting process and the updating process. So if we switch back. I also have the same type of implementation in place for input so that you could see that. So I have an onKeyUp
listener here that calls the handleKeyUp function and it passes an event so you can see here in this function that I update the state, I create a new piece of state called input details and I'm grabbing that target value.
So now if I come here and I just start typing then you can see every time I press a letter on the keyboard here it is going to call each one of those update statements.
So that's really helpful because imagine a scenario where you want to build a live search feature kind of like what you'd see on Google or YouTube. The way that they were able to build that was with this exact process here where you have access to all of those update methods so you may want to call a search API. Every single time a key is pressed or every time a few keys are pressed and you want to pass in all of those values to it well you would do that inside of one of those lifecycle hooks.
That's why they're so powerful and I know they can seem really confusing if you've never used them before, but hopefully now that you've seen this you kind of see that they are just some lifecycle hooks, they just give you access to perform some tasks at every stage of the components lifecycle from the very beginning so right when it's first called which is what the constructor does all the way through until you leave and that's where the unmounted process occurs. So as I leave the workflow you can see it calls componentWillUnmount
and where this is incredibly helpful.
We're going to walk through the other a couple of features of this project shortly and where this is really helpful is that imagine that you have some kind of live process happening. So you have something where maybe you have a timer, maybe you have a live data feed you don't want that happening in the background so componentWillUnmount allows you to have one method that you can be completely confident that as you're leaving and so as you're moving onto a different component changing pages anything like that you can perform all of your cleanup all in one spot and so this is very helpful.
Now with all of this in place hopefully this makes a lot more sense now. And now let's go and actually build something practical because hopefully, this helps to clarify it in your mind. But I think it's really helpful to build out real functionality so we're going to add some live behavior to the discussion component and then we're going to see how we can use a couple of the more popular lifecycle method hooks in order to make that possible.
So we're going to finish off by let's close out each one of these components just to make it clear what we're working on and inside of our discussion.js
file. I'm going to build out three full components here. We're going to have a discussion a discussion list and then a discussion message. Now I think we've gone through several times on how you can create a component and call it from a file. And so I'm not going to separate these out into their own separate ones just because I think it is very beneficial to see exactly what is happening here. So you're going to be able to see multiple lifecycle methods in different components and you're going to see how they can all interact with each other.
So let's start off by building out this discussion component here. I'm going to come up to the top and I'm going to add a constructor function. And inside of it, we're going to call super just like we normally do. And then let's just declare some state. So I'll say this.state
and inside of it we'll set up a page title and then this will be the discussion and then I also want to set the current time. And you'll see why here in a second, so I'll say current time and then I'm going to wrap up a new date so you could call new date like this
discussion.js
this.state = { pageTitle: 'Discussion', currentTime: new Date() }
but that's technically not going to work. What we need to do is wrap this all up and convert it into a string, so that is going to give us the current time.
discussion.js
export default class Discussion extends Component { constructor() { super(); this.state = { pageTitle: "Discussion", currentTime: String(new Date()) }; } }
and we're eventually going to build out an automated way for showing the current time and also having it update every couple seconds or every second we can change it to be however we want. So this is our constructor and now let's render this onto the screen. So we're already saying discussion but let's get rid of all of this and I'm going to put this on a few different lines so I'm going to have a div here because every component that we have has to be wrapped in a div or in some type of enclosing element. And now let's have a page title, so we're going to call this.state and then page title and let's close it off
discussion.js
render() { return ( <div> <h1>(this.state.pageTitle</h1> </div> ) }
and let's just make sure that that first part is working. So if I click on discussion you can see it shows discussion
so that is our page title and it's in an h1.
Now one thing that's kind of cool that I want to show you. And if you remember back to what I said we were going to cover if you go to the readme you may have seen this word right here object deconstruction. This is something that is inherent to JavaScript, so this isn't something in react but you will see this used quite often in react in tutorials and other documentation so I want to show you how you can do it.
So let's say that we don't want to type this.state.pageTitle
every time. But instead we just want to call pageTitle, well there's a very helpful way that we can do that. So inside of the render function here I'm going to create a const variable and using the curly brackets I can say pageTitle and then set this equal to this.state
discussion.js
render() { const { pageTitle } = this.state; return ( <div> <h1>{pageTitle}</h1> </div> ); }
and now what I can do is I don't have to call this.state anymore. I can just call pageTitle and treat it just like a variable and you can see that this is still working.
So this is really helpful because imagine that you had 10 different variables you wouldn't want to call this.state in each one of them, but instead, you'd want to be able to simply call them by their name. Now you can also add on to this so I could say pageTitle and then I could also say current time because that is available in our state and then down below I'll create another div and inside of this, I'll say this. I'm sorry I don't have to do this now, now I can just say currentTime
I would have had to do that if I wouldn't have wrapped it up with that object deconstruction.
discussion.js
render() { const { pageTitle } = this.state; return ( <div> <h1>{pageTitle}</h1> <div>{currentTime}</div> </div> ); }
So now if I save this you can see it's showing the current time.
So what's going on right here? Well with the way deconstruction works is when you wrap up these names inside of curly brackets and then you set it equal to an object which remember state's just an object what javascript is going to do is it's going to go and it's going to try to match this name with the key in the object and so this is really helpful so that we can just call the key itself and it's because we deconstructed that object, we deconstructed the state, so that is something that is definitely very helpful.
So now let's build out our little timer function. So what I want to do is every second I want the time to update on the page. Right now it's just hardcoded. Now if I hit refresh then it changes the time but you wouldn't want to have to ask your users to hit refresh for that so let's see how we can build this out. So from a lifecycle perspective, we have a constructor and then down below what we're going to do is once it's loaded then I want to start a timer. So how do you do that?
Well, if you remember we have a very special method here called componentDidMount
so I can say componentDidMount
and we are not going to pass in any arguments or anything to it and let's just log this out first. So let's just say I want to log this out and say 'Mounted component for discussion'. Hit save and let's just see if this works, and yes. So if I click on rules and then click back on discussion you can see it says mounted component for discussion.
so it loaded so that we know that this function is working I'm gonna get rid of that console log statement. So now let's actually build out the interval function so I'm going to take one approach first and then I'm going to show you how using lifecycle methods you can improve it. So when it comes to learning lifecycle the one thing that helped me the most was actually seeing how to do it wrong and when I saw how to do it wrong it showed me the importance of implementing the correct types of methods, so hopefully that approach works for you as well.
So I'm going to create a timer so I'm gonna say this. or actually, before I can do this set state I'm going to set the interval. So let's set the interval, and I'm going to pass the interval a function which is what you need to do in order to get a timer going and make sure you have your curly brackets going just like this.
So inside set interval what I want to have happen here is I want to set the state so I'm gonna say this.setState
and inside of this I want to update the time every second so I can do that by saying current time and then wrapping it up just like we did up top so I can say string new Date. And that's going to give us a new time and then I want to do it every thousand milliseconds which also means just one second.
discussions.js
componentDidMount() { setInterval(() => { this.setState({ currentTime: String(new Date())}); }, 1000); }
So I'm going to save this and let's see if this is working, and yes it is. So right here you can see what's going on here is giving us our time and then every second this is updating.
So if we click on React this is going to give you some helpful insight into what's going on and also show you how performant the entire system can be. So inside of the switch statement, we're going all the way down and now we finally have our timer.
So if you notice how this is changing you'll also notice how the state is updating and it highlights every time that updates(once a second).
This is changing but one thing that's pretty cool is in the entire application there's only one thing that is actually changing and if we were to add a component will update function so if we did something like this. So let's go and grab one of those so in updating if we wanted to put something like componentWillUpdate
and we wanted to put that inside. If you want to reference this also you can go in the workflow so you can see componentDidUpdate
we can copy just this entire line and you can see that this is also firing automatically.
So if you wanted to trigger anything inside of the update process then you can also do that here.
discussion.js
componentDidMount() { setInterval(() => { this.setState({ currentTime: String(new Date())}); }, 1000); } componentDidUpdate() { console.log("componentDidUpdate"); }
So now if we switch back and come back to the console you'll see that every second component is updating.
So this is pretty cool but there is a bug and so this is what I want to show you. We're going to be able to use the lifecycle methods in order to get this working. So with this componentDidMount here what I'm doing is I'm accidentally causing a pretty nasty memory leak right here. Now it's not that bad because we are just adding and calling the new date every second so that's not horrible. But imagine a scenario where you have like a chat feature and that's kind of what we're mimicking here we have this discussion.
Imagine that each eats each second a new chat message came in and also in the project I have this even more built out so I have some more components that you can reference. But we're almost at an hour into this deep dive so I don't want to take up too much more of your time but I do provide other examples in there but right now just imagine that with each new second you get a new discussion post. Well if you are calling an API and you have that live feed of data that's fine for when someone is looking at this. But the problem is what happens when they go and they navigate to some other spot of the app?
So let's add a console log statement inside of here so I'm going to come and lets inside the componentDidMount let's see the best spot to put this, will actually let's put it right inside of the set interval here, so I'm going to say just log and we'll just say new chat message or discussion post or whatever you'd like to call it, and so now you can see that we get a new chat message every second.
We can remove our componentDidUpdate
call here since it's really just kind of duplicating what we already had and so now we can see our mimic chat messages that are coming in once per second.
Now, watch what happens if I click on rules here, you're going to see we get a warning.
So it says can't call setState on an unmounted component. So that isn't that clear, but then read the next sentence it says this is no-op, but it indicates a memory leak in your application and that is what's happening because look at this, our chat messages are still coming in, that is not good. So what we've effectively done is it's almost like all of those processes in the client they're still occurring, we're still getting those chat messages and it's because the component is still technically active. So it's still calling that so even though we've left the component and it's hidden, or it's it's not in the DOM anymore, this set interval process is still occurring. That is a problem and this is one of the most critical things to understand when it comes to working with lifecycle methods.
So I'm going to show you how to fix this and we're going to be able to use another lifecycle method in order to do it. So here what I'm going to do is I'm going to set this entire process this setInterval process in a variable. So I'm gonna say this.liveTime which is not a reserved word or anything this is just a variable that I'm adding to the component.
discussion.js
componentDidMount() { this.liveTime = setInterval(() => { console.log("New chat message"); this.setState({ currentTime: String(new Date())}); }, 1000); }
So now it's stored in the variable. Now if I save this everything still works the exact same way. So if I click on discussion then you can see everything is still working on our chat messages are coming up it's logging them, everything's working there. But now watch how we can fix this, so now if I come down here and I say componentWillUnmount just like this.
What I can do is I can stop and I can perform all the clean up that we want to do. So right here I can say clear interval which is a way you can clear interval and then say this.liveTime
.
discussion.js
componentWillUnmount() {
clearInterval(this.liveTime);
}
And so what this is going to do is now whenever React realizes that we are clearing the component that it's unmounting it's going to call this function, this function isn't going to stop this process. In an application where you had a live data feed coming in you could simply call whatever you need to in order to break that connection. So right here we are just calling clearInterval it is clearing it and also just so it's clear you can use this process to call an API.
I wouldn't do that every second because that could be very bad from a performance perspective but let's say every 30 seconds you want to update a report on a dashboard or something. You could do this exact same thing right here, you could set the state, you could call that API, you could bring the data in, and then you can use clearInterval in order to clear that process out. That's why you needed to save it inside of a variable and save it to the object, so now let's see if this is working.
As you can see we have everything working here, we are at new chat message number 67, everything there appears to be working. Now if I click on rules it stopped, that means that everything worked. So this is how you can leverage lifecycle methods not just to help spawn processes but also to help clean them up and to perform the kind of work that you want to do. If you're wanting to just really make sure that you don't have a performance issue.
So this is something that is very critical whenever it comes to working with lifecycle methods. If you have any kind of live data or any kind of automated process that's running in a component. You just need to make sure that you clean it up and the componentWillUnmount
lifecycle method allows you to do that. So this is the full process so right here you can see that we're using four of the lifecycle methods we're using the constructor componentDidMount
, componentWillMount
, and render
.
We've seen how you have a few more, I believe eight or nine total ones to use and you're not going to use each one of them each time. So there will be many times where you only use a couple of them you may have plenty of examples where you're not even going to use any of them besides a constructor and a render. But whenever you need to add some more advanced behavior such as starting up a process or cleaning it up then these are incredibly helpful.
My goal in this entire deep dive was to really strip away some of the more confusing aspects of lifecycle methods and hopefully make it seem more straightforward and I hope that I did that. Now, if you still have questions or you are still a little confused on it then I highly recommend for you to go through the project that I created because I did add some additional examples if you go on components and you click on discussion I show how you can have multiple components all here in the same file. And some of the other components so I created a discussion list one and a discussion message and I showed how you can start that same process.
So right here
I went through and built out an automated process for creating messages and adding them to an array and then showing those on the screen, it's identical to what we did with our interval. But if you feel like you still need a little bit more clarification then I recommend that you reference this and you go through this example because it's going to show you how you can have multiple components and how you can perform that same process.
Notice here where we're doing exactly what we did in our tutorial, where we call componentWillUnmount
, we clear the interval which in this case we're clearing that message adder that I showed you. And then it's going to perform the exact same process that we did. So I hope you enjoyed it, I know that was a long guide but I hope that it helped to really add some clarification for the entire lifecycle process method inside of react for you, and good luck with the coding.
Course Update
"webpack": "^4.20.2", "webpack-cli": "^3.1.1",