CS50 Video Player
    • 🧁

    • 🍨

    • 🍇

    • 🍿
    • 0:00:00Introduction
    • 0:15:00User Interfaces
    • 0:01:09Single Page Applications
    • 0:19:03Scroll
    • 0:32:21Animation
    • 0:52:37React
    • 0:00:00[MUSIC PLAYING]
    • 0:00:17BRIAN YU: Welcome back, everyone, to Web Programming with Python and JavaScript.
    • 0:00:21And last time, we took a look at JavaScript--
    • 0:00:23that language that ran inside of a user's web browser, client side,
    • 0:00:26and allowed us to do a number of things to make our web pages more interactive.
    • 0:00:30JavaScript enabled us to display alerts, to be
    • 0:00:33able to manipulate the DOM, the structure of the web page,
    • 0:00:36in order to add content or see what content was already there.
    • 0:00:39And it also let us respond to user events.
    • 0:00:42When a user clicked on a button or submitted a form or typed something
    • 0:00:45into an input field, we could have JavaScript functions
    • 0:00:47run that responded to those events in order
    • 0:00:50to make our web pages more interactive.
    • 0:00:52Today, we're going to continue that conversation, in particular taking
    • 0:00:55a look at user interface design, looking at some common paradigms in terms
    • 0:00:59of user interfaces and how we can leverage JavaScript
    • 0:01:02to be able to achieve those goals to create interactive user interfaces that
    • 0:01:06will be valuable when users are interacting with our applications.
    • 0:01:10So one of the more common paradigms, especially nowadays, in web programming
    • 0:01:14is the idea of single-page applications.
    • 0:01:17Thus far, if we've wanted to create a web application that
    • 0:01:19has multiple different pages, we've generally
    • 0:01:22done that via multiple different routes in our Django web application,
    • 0:01:25for example, where you go to slash something to get one page
    • 0:01:28and slash something else in order to get another page.
    • 0:01:31But commonly, using JavaScript, we have the ability
    • 0:01:34to create single-page applications where the entire web page is really
    • 0:01:37just a single page, and then we use JavaScript to manipulate the DOM,
    • 0:01:41to replace portions of the page with things we want to replace.
    • 0:01:44And this has a number of advantages, one of them being that we only
    • 0:01:47need to make modifications to the part of the page that is actually changing.
    • 0:01:51If, for example, you have five different pages,
    • 0:01:53but the general layout and structure of the page
    • 0:01:55is pretty similar, when you switch between pages
    • 0:01:58rather than load an entirely new page, you
    • 0:02:00can just load the part of the page that is changing.
    • 0:02:02And this is especially helpful for applications
    • 0:02:05that are changing quite frequently.
    • 0:02:07So let's take a look now at how we could implement, for example,
    • 0:02:09a very simple single-page application.
    • 0:02:12So let's imagine, for example, that we want a single-page application that
    • 0:02:16just displays three different pages, but all included in the same page.
    • 0:02:21I'll go ahead and create a new file that I'll call singlepage.html,
    • 0:02:26inside of which we'll include our usual HTML tags.
    • 0:02:33And inside the body of this page now, I'm
    • 0:02:35going to include three different sections of the page
    • 0:02:38to represent the three different pages I might want to display to the user.
    • 0:02:42So I'll have a div whose ID is page1 that maybe just has
    • 0:02:46a heading that says "This is page 1."
    • 0:02:47And you could imagine there's more content on these pages as well.
    • 0:02:50A div whose ID is page2.
    • 0:02:53We'll say, "This is page 2."
    • 0:02:55And then one final div whose ID is page3.
    • 0:02:59It has a heading that says "This is page 3," for example.
    • 0:03:03Now, right now if I were to open up singlepage.html, what we'd see
    • 0:03:07is we see all three pages at the same time.
    • 0:03:10I know that's probably not what we want.
    • 0:03:12What we really want is by default to hide these pages
    • 0:03:14until we want to view the pages one at a time, for example.
    • 0:03:18So one thing I could do is use CSS to be able to toggle whether or not
    • 0:03:22something is visible, adding some style tags
    • 0:03:24to my page to say that by default, all of my divs
    • 0:03:28should have a display property set to none, meaning they're not visible,
    • 0:03:32they're not displayed on the screen.
    • 0:03:35Now, if I refresh the page, I don't actually see any of the three headings
    • 0:03:38that I had there before.
    • 0:03:40But what I'd really like is for some buttons
    • 0:03:42now to allow me to toggle between these three pages.
    • 0:03:45So I'll give myself three buttons--
    • 0:03:46one button that says Page 1, one button that says Page 2,
    • 0:03:50and one button that says Page 3 for example.
    • 0:03:53And I need some mechanism for these buttons
    • 0:03:55to know when you click on this button, what page should be displayed.
    • 0:03:59So I'll go ahead and use data attributes, which
    • 0:04:01we saw last time with JavaScript, to add some additional information
    • 0:04:04to these particular HTML elements, where I'll
    • 0:04:07give the first button a data-page value of page1,
    • 0:04:12the second one a data-page value of page2,
    • 0:04:15and the third one a data-page value of page3.
    • 0:04:19Here, again, just providing information so that later,
    • 0:04:21when I write some JavaScript, I can have the JavaScript code look
    • 0:04:24at the data-page attribute to say that when you click on this button,
    • 0:04:28you should let me see the div whose ID is page1.
    • 0:04:32That's what this is going to allow us to signal.
    • 0:04:35So now let's go ahead and write that JavaScript.
    • 0:04:38What I want to be able to do is to be able to say,
    • 0:04:41I would like to show page 1 and hide the other two, or show page 2
    • 0:04:44and hide the other two, or show page 3, for example.
    • 0:04:47And so to do that, I'll first write a function that will let me do that.
    • 0:04:50I'll write a function called showPage that
    • 0:04:53takes as its argument what page I want to show.
    • 0:04:56And so what should this function do?
    • 0:04:58Well, what we're going to do is we're going to say document.querySelector.
    • 0:05:02And I want to get the thing that has a particular ID the ID of whatever
    • 0:05:07this input happens to be.
    • 0:05:08This page is going to represent the ID of the div that I want to show.
    • 0:05:12So I'll say, get me the thing that has this ID.
    • 0:05:14And then using a template literal, I'll say, all right,
    • 0:05:16get me the ID of page, whatever element has that particular ID.
    • 0:05:22And then I'd like to change its style property.
    • 0:05:24Which part of the style?
    • 0:05:25Well, I want to change its display property.
    • 0:05:27And instead of none, which was the default here,
    • 0:05:30where I said don't show it at all, the other option for a div
    • 0:05:33is block, meaning it shows up as just a block that is
    • 0:05:36on the page that is actually visible.
    • 0:05:39And so now I have this showPage function.
    • 0:05:41And I can test it, in fact.
    • 0:05:42If I go into my browser, refresh the page, I now see three buttons.
    • 0:05:46The buttons don't do anything just yet.
    • 0:05:48But what I can do is in the console, if I actually just try running this,
    • 0:05:52I can run the showPage function and say, like, showPage("page1"), for example,
    • 0:05:56press Return, and all right.
    • 0:05:58Page 1 now appears on my page.
    • 0:06:00And if I [INAUDIBLE] showPage("page2"), then page 2 will become visible.
    • 0:06:04And all right, that did half of what I wanted.
    • 0:06:06Page 2 is now visible, but so is page 1.
    • 0:06:09So I probably want it such that if I ever show a page,
    • 0:06:12I hide the other pages first.
    • 0:06:14Like, hide all the pages and then show page 2, or hide all the pages
    • 0:06:17and then show page 3.
    • 0:06:19So how could I go about doing that?
    • 0:06:21Well, first, I might want to just, when I show a page, first
    • 0:06:24hide all of the other pages.
    • 0:06:26Hide all the pages.
    • 0:06:27So to get all the pages, I'll do document.querySelectorAll.
    • 0:06:32Get all of the divs, which is what I'm using to enclose the pages.
    • 0:06:36And now for each one of those-- again, effectively creating a loop where
    • 0:06:40I'm looping over each of the divs--
    • 0:06:42for each div, let's go ahead and set the div.style.display display
    • 0:06:46property equal to none.
    • 0:06:49And so what this showPage function is now doing
    • 0:06:52is it is first querying for all of the divs, which
    • 0:06:55are simulating my pages inside of this single-page application.
    • 0:06:58And for each one of the divs, we're going
    • 0:07:00to pass it as input into this function, which is the argument to forEach,
    • 0:07:04again using this arrow function notation, which is just a shorthand
    • 0:07:07way of expressing a function.
    • 0:07:09Where I'm here saying that for each of the div,
    • 0:07:11we'll go ahead and modify its style property,
    • 0:07:13setting display equal to none, meaning don't show any of the divs,
    • 0:07:17and then show only the div that was requested.
    • 0:07:21So now this should solve the problem of multiple pages appearing
    • 0:07:24simultaneously.
    • 0:07:25But if I go back to this page and I click or write showPage("page1"),
    • 0:07:31then page 1 appears.
    • 0:07:32But if I run showPage of page 2, then page 2 appears but page 1 disappears.
    • 0:07:38And likewise, when I ShowPage("page3"), that shows page 3,
    • 0:07:43but not the other two.
    • 0:07:44So I can manipulate which page is visible all via the console,
    • 0:07:48but now what I'd like to do is get these buttons to actually work,
    • 0:07:50where if I click on one of the buttons, that has the effect of actually
    • 0:07:53displaying the requested page.
    • 0:07:56So in order to do that, well, I want to attach some event listeners
    • 0:08:00to these buttons, which means I need to wait until those buttons have loaded
    • 0:08:03onto the page.
    • 0:08:04So we'll use document.addEventLis tener('DOMContentLoaded'), again,
    • 0:08:10waiting until all of the content on the page has been loaded.
    • 0:08:13And then and only then will I say, let's go ahead
    • 0:08:17and querySelectorAll for all of the buttons.
    • 0:08:21And for each one of those buttons, let's go ahead and attach an event listener
    • 0:08:25to each of those buttons.
    • 0:08:26So I'm querying for all of the buttons and saying, for each of the buttons,
    • 0:08:30I would like to do this with each button.
    • 0:08:32And what I'd like to do is say button.onClick.
    • 0:08:35When the button is clicked on, go ahead and run this function.
    • 0:08:39I'd like to showPage, and which page do I want to show?
    • 0:08:42Well, I want to show whatever page is in the page part of the buttons data set.
    • 0:08:47And to get it the current button, the button that has been clicked on,
    • 0:08:51recall that when we're inside of an event handler,
    • 0:08:53we can take advantage of the JavaScript keyword
    • 0:08:55this, which refers to whatever element has received the event,
    • 0:08:58so whatever button, in this case, that was clicked on.
    • 0:09:01So I can say this.dataset.page to mean that all right,
    • 0:09:06for each of the buttons, when the button is clicked on-- we're saying
    • 0:09:09button.onClick for each of the buttons--
    • 0:09:11run this function when the button is clicked.
    • 0:09:13We'd like to show a page.
    • 0:09:14Which page do we want to show?
    • 0:09:16We'll take this button, the button that received the event,
    • 0:09:19access its data properties, access its data page attribute,
    • 0:09:23which are down here-- either page1 or page2 or page3--
    • 0:09:27and go ahead and just call the showPage function that we wrote a moment ago.
    • 0:09:32So now that we've done that, we've attached these event handlers
    • 0:09:36to the buttons.
    • 0:09:37So now if I refresh the page, I can click on these buttons
    • 0:09:40and toggle between any of the three pages.
    • 0:09:43And now the interesting thing here is that we now
    • 0:09:46have the ability to just, in a single page,
    • 0:09:48allow myself to simulate the idea of having multiple pages, all enclosed
    • 0:09:52in a single HTML file but not needing to consistently make
    • 0:09:56additional requests to a server in order to get access to that information.
    • 0:10:00Now, sometimes, though, it might be reasonable to want
    • 0:10:02to reach out to a server--
    • 0:10:04when you need new information for a page, for example.
    • 0:10:06You might imagine that each of these pages contains a lot of text.
    • 0:10:09It's going to be inefficient if immediately, we're
    • 0:10:12loading all of that data into HTML and just showing and hiding them
    • 0:10:15when we need to, because maybe we're loading
    • 0:10:18more information than the user is ever going to actually care about,
    • 0:10:20if they're never going to look at page 2 or page 3.
    • 0:10:23So one thing we might imagine doing is loading this data dynamically.
    • 0:10:27Last time when we were talking about JavaScript,
    • 0:10:29we saw how we could use fetch to say go ahead
    • 0:10:32and request some additional information from a web server-- last time,
    • 0:10:35it was currency exchange rates.
    • 0:10:37But then we used that data that came back in order
    • 0:10:39to fill in something onto our page.
    • 0:10:41And likewise, we could do a similar thing here--
    • 0:10:44that if we have the general structure of a single page
    • 0:10:47and we want to load new content, rather than load entirely
    • 0:10:50new HTML content and reload the entire page,
    • 0:10:53we can just ask our own web server for what part of the page
    • 0:10:57needs to change and then just replace that part of the page.
    • 0:11:01And so that's what we'll take a look at now,
    • 0:11:03now combining Django for our server and JavaScript
    • 0:11:07for writing the client-side code to be able to generate
    • 0:11:09a single-page application.
    • 0:11:11And so for this, we'll go ahead and go into an example
    • 0:11:14I had in advance called singlepage1.
    • 0:11:17And inside of singlepage1, this is just a Django application
    • 0:11:20with a single app called singlepage.
    • 0:11:22And what we'll notice is we'll go to the URLs first.
    • 0:11:25There are two URLs--
    • 0:11:27one default URL that just loads the index function, and then a URL
    • 0:11:31for loading different sections of a page that I might want to dynamically load,
    • 0:11:34for example.
    • 0:11:35So I have sections/ some particular number.
    • 0:11:38And if we look at the views for what it is these URLs are actually doing,
    • 0:11:41the index function just returns index.html.
    • 0:11:45And then what the section function does is
    • 0:11:47it first makes sure the number is between 1 and 3,
    • 0:11:50and if so, responds with one of these just strings of text, for example.
    • 0:11:55So how does this actually work?
    • 0:11:57If I go into singlepage1 and run the server,
    • 0:12:04if I go to this URL /sections/1, for example,
    • 0:12:08what I get is this block of text.
    • 0:12:11And if I go to /sections/2, I get that block of text.
    • 0:12:15/sections/3, a different block of text altogether.
    • 0:12:18So just different text, and I'd like to incorporate this text into an existing
    • 0:12:23HTML page, for instance.
    • 0:12:25So here, I'll go into index.html, this template that gets
    • 0:12:28loaded when I go to the default route.
    • 0:12:31And inside of index.html, what we'll see is
    • 0:12:36I have a showSection function that behaves
    • 0:12:39very similar to the showPage function we saw from a moment ago,
    • 0:12:42but instead, what showSection is going to do
    • 0:12:45is it's going to fetch what text I should display
    • 0:12:47on the page from my own web server.
    • 0:12:49I'm fetching from /sections/ fill in a number here, number 1 or 2 or 3.
    • 0:12:56When I get the response, in the past we've
    • 0:12:59seen how we can convert that response into JSON data,
    • 0:13:01if it's unstructured data.
    • 0:13:02We can also just convert the response into plain text.
    • 0:13:06Then I'll take that text, console.log it just
    • 0:13:09so we can see it in the log output.
    • 0:13:10But then go ahead and query select for the content of the page, something
    • 0:13:14that has an ID of content, update its inner HTML,
    • 0:13:17and set it equal to that text.
    • 0:13:19So what this entire function is now doing
    • 0:13:21is it is going to reach out to my server,
    • 0:13:23figure out what text content belongs in the new section,
    • 0:13:26and fill in the part of my page accordingly with the text that
    • 0:13:31comes back from that HTTP request.
    • 0:13:34And then down further below, inside of the page,
    • 0:13:36we'll see that I have a Hello heading, three buttons that
    • 0:13:40toggle between the different sections.
    • 0:13:42Each of them has a data-section attribute this time
    • 0:13:45for which section should be loaded.
    • 0:13:47And then a div that is initially blank just for the content of the page.
    • 0:13:52So putting this all together now, if I go to the default route,
    • 0:13:56I see "Hello!" plus three buttons to give me
    • 0:13:58a choice between three different sections.
    • 0:14:00And if I click Section 1, what's going to happen is JavaScript is going
    • 0:14:03to query /sections/1, ask for the text.
    • 0:14:07It gets that text back, and it's going to fill it in into the page--
    • 0:14:11Section 1, Section 2, and Section 3.
    • 0:14:14So very similar to before, but unlike what we had before,
    • 0:14:17where all of the text was being loaded into the HTML page all at once,
    • 0:14:21now we're using asynchronous JavaScript to only dynamically load
    • 0:14:25information when we need it.
    • 0:14:26When we click on a section, then it's going
    • 0:14:28to make the request for what content needs to be filled in,
    • 0:14:30and it's going to fill it in.
    • 0:14:32And everything else-- these buttons, this
    • 0:14:34heading, and you might imagine in a more complex website,
    • 0:14:36you've got a lot more going on around the edges of this web page--
    • 0:14:39and all of that stays the same.
    • 0:14:41We don't need to reload any of that information.
    • 0:14:43We're only reloading the portion of the page that
    • 0:14:46actually changes as we toggle between these various different section
    • 0:14:50headings.
    • 0:14:51Now, this seems to be an advantage in some ways,
    • 0:14:53that maybe we can be more efficient about how we run
    • 0:14:55our single-page applications like this.
    • 0:14:57One thing we seem to lose, though, is the notion
    • 0:15:00of maintaining state inside of the URL.
    • 0:15:02That generally, the URL gives you an indication for what page you're on.
    • 0:15:06You're on something like /1 if you're on section 1 or /2 if you're on section 2,
    • 0:15:11/3 for section 3.
    • 0:15:12But of course, we're staying on the same page in all of these examples.
    • 0:15:15Whenever I click a button--
    • 0:15:17Section 1 or 2 or 3--
    • 0:15:18the URL is never changing.
    • 0:15:20The URL stays the same.
    • 0:15:21It turns out there's a way in JavaScript to manipulate that URL,
    • 0:15:25taking advantage of what's known as the JavaScript history API, where
    • 0:15:29I can push something to the history, meaning update the URL
    • 0:15:33and actually save that inside the user's browser history so later on,
    • 0:15:36they could potentially go back to that.
    • 0:15:39And to do that, I'll show you yet another example inside of singlepage2,
    • 0:15:44which is very similar, except inside of index.html,
    • 0:15:48I've added a couple of additional things.
    • 0:15:51One is that when I click on a button, meaning
    • 0:15:53when I click on Section 1 or Section 2 or Section 3,
    • 0:15:56I've added this line here, history.pushState.
    • 0:16:00What history.pushState is going to do is it
    • 0:16:03is going to basically add a new element to my browsing history, where I first
    • 0:16:07specify any data associated with the state.
    • 0:16:10So in particular, I'm storing a JavaScript object
    • 0:16:13representing what section number is being represented here.
    • 0:16:16Next is a title parameter that most web browsers actually ignore,
    • 0:16:20so that can generally be the empty string.
    • 0:16:21But the third argument here is what should go in the URL.
    • 0:16:24And what I want to go in the URL, in this case,
    • 0:16:26is something like section followed by the section number.
    • 0:16:29So I can go to /section1 or /section2 or /section3, for instance,
    • 0:16:34and those will appear in the URL bar when I click on a different page.
    • 0:16:39Then what I want to be able to support is the ability
    • 0:16:42to say when I go back through my history,
    • 0:16:44if I click the Back button in my web browser,
    • 0:16:46I'd like to go back from section 3 to section 2,
    • 0:16:49if that was the page I visited previously.
    • 0:16:51And there turns out to be an event handler for that as well--
    • 0:16:54window.onpopstate, meaning when I pop something off of the history,
    • 0:16:59like go back in my history, we have the ability
    • 0:17:02to take some event as an argument.
    • 0:17:04And if you look at event.state.section, which I've run console.log on,
    • 0:17:09so we can take a look at it in a moment, we'll
    • 0:17:11see what state was stored associated with that part of the user's history,
    • 0:17:15and I can go ahead and show that section.
    • 0:17:18So all in all, when I run this web application,
    • 0:17:21going into singlepage2 this time, when I run the server, I see "Hello!",
    • 0:17:29three sections for buttons.
    • 0:17:31When I click on one of those buttons, not only do I see text,
    • 0:17:34but I also see in the URL bar that I'm now on /section1.
    • 0:17:38That has been pushed onto my history, and I've
    • 0:17:40updated the URL to reflect that, too.
    • 0:17:42I click Section 2.
    • 0:17:43That updates the URL as well.
    • 0:17:45Section 3 updates the URL, too.
    • 0:17:47And when I've pushed things onto my history,
    • 0:17:49I've associated some state with them so that I can go back if I ever need to.
    • 0:17:54And in fact, if I open up the JavaScript console now and I go back, for example,
    • 0:17:58back to section 2, what you'll see is that what gets logged is the number 2.
    • 0:18:03When I print out what is the current section that's
    • 0:18:06associated with this URL, it's saving that state,
    • 0:18:08that I should be loading section number 2.
    • 0:18:11And so it does load section number 2 here.
    • 0:18:15So there's certainly nothing wrong with the original paradigm
    • 0:18:17of just loading different pages dynamically using Django,
    • 0:18:20like make a request and get a response.
    • 0:18:22But oftentimes, as you begin to imagine applications where a lot of things are
    • 0:18:26changing on the same page simultaneously--
    • 0:18:28you might imagine social networking websites where a lot of things stay
    • 0:18:30the same, but new posts might be added and you might be looking at different
    • 0:18:33parts of the same page--
    • 0:18:35being able to dynamically load information,
    • 0:18:37request additional information, and then display it on the page
    • 0:18:40can actually be quite powerful and a way to make your web pages a little bit
    • 0:18:44more interactive.
    • 0:18:46So that then is how we might build single-page applications-- taking
    • 0:18:49advantage of JavaScript to asynchronously load new data,
    • 0:18:52and then taking advantage of this history API
    • 0:18:55that let us add things to the URL, add things to the user's browsing history,
    • 0:18:58such that we could go back to them later by listening for window.onpopstate.
    • 0:19:03And it turns out that window object that we get access
    • 0:19:06to in JavaScript is quite powerful.
    • 0:19:08It represents the physical window on the computer screen
    • 0:19:11that displays all of their web content.
    • 0:19:13And there are certain properties of that window
    • 0:19:15we can look at that allow us to enable some interesting features.
    • 0:19:18So for example, your window is really described
    • 0:19:20by what the user actually sees inside of their window in Google Chrome or Safari
    • 0:19:25or whatever web browser they happen to be using.
    • 0:19:27And there are a couple of properties that might be of use.
    • 0:19:29Something like window.innerWidth will represent
    • 0:19:32how wide is the window, which might be useful to know
    • 0:19:35to know the size of the user's screen, for example, to know how many pixels
    • 0:19:39wide the window happens to be.
    • 0:19:41And just as there's a window.innerWidth, there's
    • 0:19:43also a window.innerHeight that represents the height of the window
    • 0:19:47as well.
    • 0:19:49Now, window represents the physical part that they're actually seeing.
    • 0:19:52We've also seen another variable that JavaScript gives us access to,
    • 0:19:55and that is this document object.
    • 0:19:57So what is the difference between the window and the document?
    • 0:20:00Well, the document generally represents the entire web page.
    • 0:20:03But if web pages are long, oftentimes the web page
    • 0:20:06doesn't fit entirely inside of the window--
    • 0:20:08that you generally have to scroll through an entire web page
    • 0:20:11and the window is only showing you one portion of that page at any given time.
    • 0:20:15So you can represent the document as, like, this big vertical section
    • 0:20:19that goes beyond the window.
    • 0:20:20There might be part of the document that is
    • 0:20:22above the window, part of the document that is below the window as well.
    • 0:20:26So window.scrollY is another variable you have access to on the window,
    • 0:20:31and window.scrollY represents how many pixels far down have you scrolled.
    • 0:20:35So if you're at the top of the page, window.scrollY
    • 0:20:38is 0-- you haven't scrolled at all.
    • 0:20:40But as you begin to scroll, if you want to know how far the user has scrolled
    • 0:20:43on a page, you can look at window.scrollY
    • 0:20:46to figure out the number of pixels the user has scrolled in the Y
    • 0:20:50direction, the up and down direction.
    • 0:20:53And the entire height of the page is represented
    • 0:20:56in document.body.offsetHeight.
    • 0:20:59That represents how tall the entire height of the document is.
    • 0:21:02And we talk about all this in addition to things like window.innerHeight
    • 0:21:05and window.innerWidth because using all of these values together,
    • 0:21:09you can begin to do some interesting calculations.
    • 0:21:12So one thing you might want to detect, for example,
    • 0:21:14is has the user scrolled down to the bottom of the page or not?
    • 0:21:18That might be something you care about knowing.
    • 0:21:20And it turns out, there isn't an event listener that does this automatically.
    • 0:21:23But we can calculate it in order to try and figure this out.
    • 0:21:26If innerHeight is the height of the window,
    • 0:21:29scrollY is how far vertically the user has scrolled,
    • 0:21:32and document.body.offsetHeight is the entire height of the document, you
    • 0:21:36can ask yourself, what needs to be true if the user has
    • 0:21:40scrolled to the bottom of the page?
    • 0:21:42And well, if the user has scrolled to the bottom of the page,
    • 0:21:45well, then scrollY plus the innerHeight, meaning
    • 0:21:49the amount that they've scrolled, plus the height of the window, that
    • 0:21:52must be at least or equal to document.body.offsetHeight, meaning
    • 0:21:56the amount that they've scrolled plus the window takes you down
    • 0:21:59to the bottom of the page, to the end of a page, to
    • 0:22:01however tall the document happens to be.
    • 0:22:04And using that mathematical comparison, we
    • 0:22:06can actually detect when the user has reached the bottom of the page
    • 0:22:11and we can actually try and now put that into practice.
    • 0:22:13So I'll go ahead and open up an example that I have here called scroll.html,
    • 0:22:19and all scroll.html has right now is 100 paragraphs.
    • 0:22:23Inside of the body tag I have a p for paragraph, paragraph 1, paragraph 2,
    • 0:22:28so on and so forth.
    • 0:22:29I have 100 paragraphs inside of the body of this HTML page.
    • 0:22:34And that's all that really is there right now, such
    • 0:22:36that now if I go ahead and open scroll.html,
    • 0:22:42I see that I have 100 paragraphs that I can scroll through.
    • 0:22:47And what I might like to do is detect when
    • 0:22:49I've reached the bottom of the page and maybe do something when I do so,
    • 0:22:52something like change the color of the page, for instance.
    • 0:22:56So how might I go about doing that?
    • 0:22:57Well, I'm going to need some JavaScript.
    • 0:22:59So I'm going to add some JavaScript, and I'll add an event listener
    • 0:23:03for window.onscroll.
    • 0:23:05Onscroll is an event that listens for when I'm scrolling through the window.
    • 0:23:10And when I scroll through the window--
    • 0:23:12we'll go ahead and run this function.
    • 0:23:13We'll just use an arrow function as a shorthand here--
    • 0:23:16what do I want to calculate?
    • 0:23:17Well, I want to calculate if window.innerHeight,
    • 0:23:21meaning the height of the window itself, plus window.scrollY,
    • 0:23:25meaning the amount that I've scrolled, if that
    • 0:23:28is at least document.body.offsetHeight, well,
    • 0:23:34that means I must have scrolled to the bottom of the page
    • 0:23:36or maybe even a little bit further, if there's a little wiggle room
    • 0:23:38to scroll past the end of the page.
    • 0:23:40So if this is true, well, then I've reached the end of the page.
    • 0:23:44And then we'll go ahead and say document.querySelector('body').
    • 0:23:49And let's go ahead and change its style, in particular change
    • 0:23:52its background color, and change the background color to green.
    • 0:23:56Otherwise, if we haven't reached the end of the page,
    • 0:23:59then we'll take the body of the page and change its background color to white.
    • 0:24:06So what we're now doing here is taking advantage
    • 0:24:08of the properties we know of this window object,
    • 0:24:11saying when we scroll the window, let's check to see if we add this up
    • 0:24:15and at least the height of the entire document,
    • 0:24:17we've reached the end of the page.
    • 0:24:19Go ahead and change the style of the background of the body accordingly.
    • 0:24:22Otherwise, change the background to white
    • 0:24:24or leave it at white if it already is.
    • 0:24:27So now if I take a look at this actual HTML page and reload scroll.html,
    • 0:24:32we'll see that the background is initially white.
    • 0:24:34But as I scroll down, once I reach the bottom,
    • 0:24:38we'll see that the page changes to green.
    • 0:24:40It's white before I reach the bottom, but as soon
    • 0:24:42as I get to the bottom of the page, it turns to green.
    • 0:24:45And the reason why is because the height of the window, height
    • 0:24:48of the window here, plus however much I've
    • 0:24:50already scrolled from the top of the page up until now,
    • 0:24:52that together is equal to the entire height of the document, which
    • 0:24:56means we're able to detect the fact that I reached the end of the page.
    • 0:24:59And as a result, we can change the color of the background to green.
    • 0:25:02Now, this in itself is not a particularly practical use
    • 0:25:05of detecting when we've scrolled to the end of something.
    • 0:25:08We probably don't usually care about changing the background color
    • 0:25:10when you reach the end of the page.
    • 0:25:12But there actually are real applications,
    • 0:25:14and you might imagine this in the context of websites that
    • 0:25:17allow for things like infinite scroll--
    • 0:25:19that if you're on a social networking website that
    • 0:25:20has a whole bunch of posts, you scroll to the bottom of the list of posts,
    • 0:25:23and then it generates the new set of posts as well.
    • 0:25:26Or you're looking at news articles and you're scrolling through news articles,
    • 0:25:29and once you reach the bottom, it'll load a whole new set of news articles
    • 0:25:32without you having to go to another page.
    • 0:25:35How is it doing that?
    • 0:25:36Well, it's a combination of the same types of ideas
    • 0:25:38that we've been talking about.
    • 0:25:39Number 1, the ability to detect when you've reached the end of the page
    • 0:25:43using JavaScript to detect that you're at the bottom of the page,
    • 0:25:46and number 2, to be able to asynchronously load, using JavaScript,
    • 0:25:50additional content-- fetch some additional page that has some
    • 0:25:53additional content, some additional news articles, some additional posts,
    • 0:25:57and whatnot--
    • 0:25:57and then take that information and manipulate the DOM
    • 0:26:00to add that information to the existing web page.
    • 0:26:03And that, ultimately, is what's going to give us
    • 0:26:05this power to be able to support something like infinite scroll.
    • 0:26:10So let's now go ahead and try and see what it would
    • 0:26:13look like to implement infinite scroll.
    • 0:26:16I've already started to create a sample application
    • 0:26:18inside of this application called scroll,
    • 0:26:21and I've got an app called posts inside of it.
    • 0:26:23And what the posts app does is it's got a couple of URLs.
    • 0:26:27It's got a default URL that just loads an index route, and then a posts route
    • 0:26:31that loads this posts view.
    • 0:26:34And so lets look at what these do.
    • 0:26:36Index, all it does is it's going to load a file
    • 0:26:38called index.html, this template.
    • 0:26:41And if I make a request to /posts, I need to provide two arguments.
    • 0:26:46I need to provide a start for what post I want to start with,
    • 0:26:50an end for what post I want to end with, and then
    • 0:26:52it's just going to generate some sample posts that
    • 0:26:54just say, like, Post number 1, Post number 2, so on and so forth.
    • 0:26:57In practice, you can actually use social network posts in place of this,
    • 0:27:01but this is good just for demonstration purposes.
    • 0:27:04So what this is going to do, if I go into scroll and runserver,
    • 0:27:13is that if I go to /posts and say start=1 and end=10, for example,
    • 0:27:21then I get a JavaScript object that looks like this.
    • 0:27:24Recall that a JavaScript object is just a convenient format
    • 0:27:27for passing information back and forth in JSON format.
    • 0:27:30And what we have here is a JSON object with a key
    • 0:27:33called posts that gives me all of the posts--
    • 0:27:35Post number 1, Post number 2, all the way up to number 10.
    • 0:27:38And it's giving me those posts because I said start at 1, end at 10.
    • 0:27:42But I could have specified other numbers as well.
    • 0:27:44If I had said something like start at 20 and go to 28,
    • 0:27:48then it's going to give me post number 20 through post number 28.
    • 0:27:52I can specify the range of posts that I want.
    • 0:27:54So this now is an API that I have implemented, effectively,
    • 0:27:58that allows someone to get access to a variety of different posts
    • 0:28:02by hitting this particular URL, this endpoint, so to speak,
    • 0:28:05and passing in parameters-- passing in what post they want to start with
    • 0:28:09and what post they want to end with.
    • 0:28:10And then they get all of this data back presented to them
    • 0:28:14in JSON format that can then be used.
    • 0:28:16And what's nice about this is that now when we're loading posts,
    • 0:28:20rather than have to just guess at how many posts we need to load
    • 0:28:22and then require someone to go to another page,
    • 0:28:25we can just do something like load the first 20 posts,
    • 0:28:28and now what we'd like to do is if they reach the end of the page,
    • 0:28:31go ahead and load the next 20 posts by hitting this API endpoint,
    • 0:28:35getting the next 20 posts, and then filling that in into the HTML page.
    • 0:28:40So let's see now how that actually works in practice by taking
    • 0:28:44a look at that template in index.html.
    • 0:28:48So go into templates, index.html.
    • 0:28:51And there's a fair bit of JavaScript here, but look at the body first.
    • 0:28:54The body just has a div for all the posts
    • 0:28:56that initially is going to be empty.
    • 0:28:59Now, here's what the JavaScript is going to do, and we'll walk through it.
    • 0:29:03We start with the first post, so counter is
    • 0:29:05going to keep track of what post we need to load next.
    • 0:29:07By default, we're just going to start by loading post number 1.
    • 0:29:10We have a variable called quantity that's
    • 0:29:12going to tell us how many posts are we going to load at a time.
    • 0:29:14Let's just say load 20 posts at a time.
    • 0:29:16So start with 1 to 20, then 21 to 40, 41 to 60, so on and so forth.
    • 0:29:21And when DOM content has loaded, go ahead and just
    • 0:29:25call this function that's called load.
    • 0:29:28And what the load function does is it figures out
    • 0:29:30what the start and end should be, it fetches all the new posts, and then
    • 0:29:35for each of the posts that comes back, is it figures out what [AUDIO OUT]..
    • 0:29:39So we're asynchronously asking for new posts.
    • 0:29:42And what the add_post function does is it creates a new div,
    • 0:29:45populates the post inside of it, and adds it to the DOM.
    • 0:29:49So now that we have these parts, the ability
    • 0:29:51to load new posts as by fetching from some URL
    • 0:29:54all of the posts that we care about, and then for each of those posts
    • 0:29:57that comes back, add something new to the DOM
    • 0:30:00as by creating a new HTML element and inserting it into the page,
    • 0:30:04we have the ability to dynamically load all of these posts.
    • 0:30:07So if I go not to /posts, but just to this default route,
    • 0:30:12I'll see that we have something like 20 posts that all show up.
    • 0:30:17But just 20 posts.
    • 0:30:19Because every time I call the load function,
    • 0:30:23that is going to load the next set of posts, for example.
    • 0:30:26And so what I can do is in the console, if I try running the load function just
    • 0:30:31by calling it myself, press Return, after a second
    • 0:30:34or so, the next set of posts show up--
    • 0:30:3621 all the way through 40.
    • 0:30:38I call load again.
    • 0:30:40The next set of posts show up--
    • 0:30:4141 through 60.
    • 0:30:4320 posts at a time, all using that asynchronous JavaScript.
    • 0:30:47But now what I'd like to happen is for all of this to happen on its own,
    • 0:30:50without me having to intervene and manually write JavaScript calls.
    • 0:30:53I would just like to say, well, the same type of logic as before--
    • 0:30:57window.onscroll.
    • 0:30:59Lets go ahead and say if window.innerHeight plus window.scrollY
    • 0:31:04is at least document.body.offsetHeight, meaning
    • 0:31:08if I have scrolled to the end of the page, well,
    • 0:31:11then just go ahead and call the load function.
    • 0:31:15That's all these lines are doing.
    • 0:31:16Every time I scroll, we check.
    • 0:31:18Did we scroll to the end of the page?
    • 0:31:20And if we did scroll to the end of the page,
    • 0:31:21then go ahead and load the next set of posts.
    • 0:31:25So now I refresh the page, I see Post #1 all the way up through Post #20.
    • 0:31:32Now watch what happens when I get to Post #20.
    • 0:31:34If I scroll to the bottom, after a second, the next set of posts appears.
    • 0:31:38I scroll to the bottom again, I'm at 40.
    • 0:31:40And then after a second, the next set appears.
    • 0:31:42Every time I scroll to the bottom, more posts are going to load after that,
    • 0:31:45allowing me to effectively implement this idea of infinite scrolling
    • 0:31:50by taking advantage of some JavaScript techniques, where
    • 0:31:52I can check for when I've got to the end of the page
    • 0:31:55and then dynamically do something as a result of that, something like load
    • 0:31:58some additional pages onto the screen.
    • 0:32:01And so here, too, a lot of power to be had inside of JavaScript.
    • 0:32:05And a lot of where the power of user interface comes from
    • 0:32:08is from how it is that the user interface interacts with the user,
    • 0:32:12thinking about what the user is going to do
    • 0:32:14and how the page should interact as a result-- something like user scrolls
    • 0:32:17to the end of the page and they see some new pages show up as well.
    • 0:32:21And one technique we can use for just making HTML elements a little more
    • 0:32:25responsive, a little bit more interesting,
    • 0:32:26is by adding some animation to them as well-- the ability for things
    • 0:32:30to move around and change their properties in some way.
    • 0:32:33And it turns out that CSS has support for animation.
    • 0:32:36CSS has already given us support for things like styling elements,
    • 0:32:40saying we want this element to be of this color and this size, for example.
    • 0:32:43But it also gives us the ability to animate those properties as well,
    • 0:32:46to change the size of something or change the position of something
    • 0:32:50over some amount of time.
    • 0:32:52And so let's now take a look at an example of what that might actually
    • 0:32:55look like.
    • 0:32:56I'll go ahead and create a new file and I'll call it animate.html.
    • 0:33:01And inside of animate.html, I'll go ahead
    • 0:33:04and start by including our usual HTML.
    • 0:33:10Title is Animate.
    • 0:33:13And what I'd like to do is just add a little bit of animation using CSS
    • 0:33:18into this particular page.
    • 0:33:19I'm going to start with just a heading, a heading that says something
    • 0:33:22like "Welcome!", for example.
    • 0:33:25It's just going to display a welcome message.
    • 0:33:27Such that now if I open animate.html, here's what I see--
    • 0:33:34just a message that says "Welcome!"
    • 0:33:36But now let's add some CSS to it.
    • 0:33:39Let's go into the style tag.
    • 0:33:41And for h1, for this heading, I'd like to apply a particular animation to it.
    • 0:33:47And I first need to specify what the animation's name is going to be.
    • 0:33:51And I can pick a name for the animation.
    • 0:33:53I'll say something like "grow," for example.
    • 0:33:57I'll set the animation's duration to be 2 seconds.
    • 0:34:00And then the animation fill-mode is like what
    • 0:34:02direction should the animation move in.
    • 0:34:04Should it go forwards?
    • 0:34:05Should it go backwards?
    • 0:34:06We'll generally want our animation to go forward,
    • 0:34:08so they're making some sort of forward progress according to some rules
    • 0:34:11that we're going to specify.
    • 0:34:13So here I'm saying we're going to animate all of our headings
    • 0:34:15using an animation called grow, and now I
    • 0:34:18need to define what that animation actually does.
    • 0:34:20And to do that, up above in style I'm going to say @keyframes grow.
    • 0:34:26And what this is going to allow me to do is
    • 0:34:28specify some keyframes for this particular element,
    • 0:34:32meaning where should the element start, what should its style properties
    • 0:34:35be, and then at the end, what should its style properties be?
    • 0:34:38And CSS is going to take care of the process of figuring out
    • 0:34:41what needs to happen in all those intermediary fractions of seconds,
    • 0:34:44for example.
    • 0:34:46So what I can say is something like, go ahead and grow from--
    • 0:34:49meaning what should its initial properties be,
    • 0:34:51and maybe initially I want it to have a font size of 20 pixels--
    • 0:34:55and then we'll say to font size of 100 pixels, for example.
    • 0:35:01So all in all, what this is saying is I would
    • 0:35:03like to apply an animation called grow to all of my headings.
    • 0:35:07This animation should last 2 seconds and go forwards.
    • 0:35:10And what is the grow animation going to do?
    • 0:35:12Well, it's going to mean at the start, anything
    • 0:35:14that obeys the grow animation will start with a font size of 20 pixels,
    • 0:35:18and at the end, it will grow to a font size of 100 pixels.
    • 0:35:22And I have now defined what it is that that animation means.
    • 0:35:26So now if I go ahead and refresh this page,
    • 0:35:29animate.html, you'll see that "Welcome!" changes size.
    • 0:35:33Over the course of 2 seconds, it goes from smaller to larger by obeying those
    • 0:35:37keyframes.
    • 0:35:37I told it to obey this particular set of instructions
    • 0:35:41where it goes from a particular font size to another font size,
    • 0:35:44and as a result, we see the effect here on the page.
    • 0:35:47And it turns out you can do more than just manipulate size.
    • 0:35:50You can manipulate just about any CSS property you want.
    • 0:35:53So if I tell the heading that it should have a relative position,
    • 0:35:58meaning its position should be relative to other elements or other things
    • 0:36:01than its parent, I can say you should change your position from being 0%
    • 0:36:07away from the left side of the screen to being 50% of the way
    • 0:36:13from the left side of the screen.
    • 0:36:14And at this point, "grow" is probably not the best name for this animation.
    • 0:36:17I'll call it "move" instead.
    • 0:36:19So animation name is move.
    • 0:36:20And so now what this animation is going to do
    • 0:36:22is it's going to say when you run the animation,
    • 0:36:24go from being right next to the left side of the screen to being about 50
    • 0:36:30away from the left side of the screen.
    • 0:36:33So I can go ahead and rerun this.
    • 0:36:37And we see that's the animation that takes place.
    • 0:36:39It goes from the left all the way back up to about halfway across the screen.
    • 0:36:44Refresh the page and it goes ahead and does the exact same thing.
    • 0:36:48And it turns out, we don't just need to specify a beginning point and an end
    • 0:36:51point for an animation.
    • 0:36:52We can specify various different keyframes for different points
    • 0:36:56within the animation that we would like to capture,
    • 0:36:58something like at the beginning of the animation,
    • 0:37:00have this set of CSS properties, maybe halfway through the animation,
    • 0:37:03have a different set of CSS properties, and then at the very end,
    • 0:37:06have yet another set of CSS properties.
    • 0:37:09So I could say something like, if I want the heading not just to move
    • 0:37:12from left to right but also to move back again, I can say at the beginning,
    • 0:37:16at the 0% point when you're 0% of the way through the animation,
    • 0:37:20you should be 0% away from the left-hand side.
    • 0:37:23When you're 50% of the way through the animation,
    • 0:37:25you should be 50% away from the left-hand side.
    • 0:37:28And then when you're done with the animation, 100% of the way through,
    • 0:37:31let's go back to 0% away from the left-hand side.
    • 0:37:35I now have three keyframes-- beginning of the animation,
    • 0:37:38middle of the animation, back to the beginning of the animation again--
    • 0:37:41and the effect of this is if I refresh the page, we go to the right
    • 0:37:45and then we go back.
    • 0:37:46We're able to move one direction and then move back.
    • 0:37:49And there are other properties we can use
    • 0:37:51to manipulate these animations as well.
    • 0:37:53I can set the animation-iteration-count, for example,
    • 0:37:56to 2, to mean rather than just do the animation once and then stop,
    • 0:38:00do the animation twice and then stop.
    • 0:38:03So I refresh, it goes to the right and then it goes left,
    • 0:38:06and then it repeats that a second time.
    • 0:38:08And it turns out if you really want, you can
    • 0:38:10set this to infinite, to mean never stop performing that animation.
    • 0:38:14It's consistently going to have this heading, move to the right,
    • 0:38:17and then move left, according to those keyframes that I have specified.
    • 0:38:20And so if you ever see things moving around on a page,
    • 0:38:22interactive in some way, there are a number of ways to do it.
    • 0:38:25You can animate things using JavaScript, for example.
    • 0:38:28But there are many cases where CSS alone is pretty good at just
    • 0:38:31creating these types of animations.
    • 0:38:33And while this animation right now is just running forever,
    • 0:38:36we could use JavaScript in order to control that animation as well.
    • 0:38:41So let's see an example of what that would look like.
    • 0:38:44I'll go back here.
    • 0:38:45In the body of the page, in addition to a heading
    • 0:38:47that says "Welcome!", I'll go ahead and add a button that
    • 0:38:51just says "Click Here!", for example.
    • 0:38:54And now what I'll do is add a little bit of JavaScript.
    • 0:38:58I'm going to add some JavaScript so that the button can now
    • 0:39:01control the animation, decide when the animation is going to start and stop.
    • 0:39:06And so what we'll do inside of the script is to first say
    • 0:39:10document.addEventLis tener('DOMContentLoaded'), meaning wait
    • 0:39:14until the DOM is done loading, as we've done before.
    • 0:39:18And let me now get that h1 element--
    • 0:39:20document.querySelector('h1').
    • 0:39:26And initially, I'm going to set its style.animationPlayState
    • 0:39:31equal to paused.
    • 0:39:34So animationPlayState is a property of the style that
    • 0:39:37lets me decide if the animation is playing or paused,
    • 0:39:40and I can control that using JavaScript.
    • 0:39:42Rather than just say run infinitely forever,
    • 0:39:44I can say the animationPlayState should start out as paused, by first getting
    • 0:39:49the h1 element and then modifying the animationPlayState property
    • 0:39:53of that particular element.
    • 0:39:56But now what I'd like to happen is any time someone clicks on the button,
    • 0:40:00I want to change the animation play state.
    • 0:40:02So I'm going to say document.querySelector('button'),
    • 0:40:05meaning get that button, and when someone clicks on the button,
    • 0:40:09let's run this function where if the current animationPlayState is paused,
    • 0:40:18well, then, go ahead and set animationPlayState equal to running.
    • 0:40:24And otherwise, if it's already running, then
    • 0:40:26let's go ahead and set the animationPlayState equal to paused.
    • 0:40:32So all in all, what this function is going to do
    • 0:40:34is it's going to get me the heading, pause this initially,
    • 0:40:37and every time the button is clicked, run this function where
    • 0:40:40the function says if we're paused, go ahead and start running the animation.
    • 0:40:44Otherwise, go ahead and pause the animation
    • 0:40:46by modifying that animationPlayState property of the heading.
    • 0:40:50So now if I refresh this page, right now we have "Welcome!" plus a button
    • 0:40:54that says "Click Here!"
    • 0:40:55And initially, everything is paused.
    • 0:40:56There's no animation happening.
    • 0:40:58But I click here and that begins the animation, which
    • 0:41:00would go on indefinitely until I decide that I want to stop it, at which point
    • 0:41:04I click it again and the animation pauses.
    • 0:41:07And I can control when to start and when to pause that animation as well.
    • 0:41:12And so this can be helpful and nice when you
    • 0:41:14want to create something a little bit more interactive,
    • 0:41:16something animated on the page.
    • 0:41:18But this is especially helpful because it means that you can gradually
    • 0:41:21change CSS properties over time.
    • 0:41:23Rather than just immediately change something,
    • 0:41:25you have the ability to animate something
    • 0:41:27to make it work a little bit better.
    • 0:41:29So let's take a look at an example of how
    • 0:41:31you might put that idea into practice.
    • 0:41:34Let's go back to our posts example, where we had this infinite scrolling
    • 0:41:38list of posts, but imagine now that we want the ability to hide posts
    • 0:41:42when we're done with them.
    • 0:41:43So I've prepared an example called hide, which
    • 0:41:47is very similar to what we had before.
    • 0:41:50But this time, I've just added one extra button and the button
    • 0:41:54says "Hide" on every single div.
    • 0:41:56Right now, clicking the Hide button does nothing.
    • 0:41:58We'll go ahead and implement that in just a moment.
    • 0:42:00But first to see how this worked, if you go into hide,
    • 0:42:03go into the index.html template.
    • 0:42:06The only change that's been made here is what happens when I add a new post.
    • 0:42:10Recall again that what this application does is it loads posts from a server.
    • 0:42:14And then when it gets to those posts, it loops
    • 0:42:16over each of the individual posts, which is just a string of text,
    • 0:42:19and it adds that string of text inside of an element
    • 0:42:22onto the page via this add_post function.
    • 0:42:25And what the add_post function is going to do here
    • 0:42:28is first create a new element, create a div in which to store that post,
    • 0:42:32give it a class name, because that's how we're going to animate it,
    • 0:42:35and then set its inner HTML equal to the contents of the post--
    • 0:42:39something like post number 1, post number 2, post number 3--
    • 0:42:42and then add a button that just says "Hide."
    • 0:42:45And then we're going to go ahead and add that to the DOM as well.
    • 0:42:49So that's what add_post is now going to do.
    • 0:42:50We're sort of generating some HTML using this JavaScript code
    • 0:42:54and then adding that HTML to the page.
    • 0:42:56And now we're adding is a div that has not only
    • 0:42:59the contents in the post as text, but is also
    • 0:43:01going to give us access to a button that ultimately we
    • 0:43:04hope is going to let us hide that post as well.
    • 0:43:08So how do we actually get the hiding of the post to work?
    • 0:43:11Well, what we want to do is somehow detect
    • 0:43:14when the user clicks on one of those Hide buttons.
    • 0:43:17So there's a number of ways we could do this,
    • 0:43:19but one way is just to listen for any time anyone clicks
    • 0:43:25on the document as a whole.
    • 0:43:28Any time anyone clicks on the document, I
    • 0:43:30might like to ask something like, what did they actually click on?
    • 0:43:34And it turns out that with most event listeners,
    • 0:43:36the function the event listener takes in can
    • 0:43:38take as an optional argument the event itself, which
    • 0:43:42is a JavaScript object that contains information about the event that
    • 0:43:46happened, like the click event or the scroll event
    • 0:43:48or the keydown event or the keyup event, for example.
    • 0:43:51And one of the properties you get access to
    • 0:43:53is event.target, which is like what was the target of the event?
    • 0:43:58In this case, what was the thing that was actually clicked on?
    • 0:44:01And I'll go ahead and save event.target inside of a variable called
    • 0:44:05element, where the idea now is that whatever gets clicked on, that is
    • 0:44:09the event's target.
    • 0:44:10We're going to save that inside of element.
    • 0:44:12And what I want to know is is element, is that one of the Hide buttons?
    • 0:44:16I want to know, is it a Hide button.
    • 0:44:18I could have also attached an event listener to each of the Hide buttons.
    • 0:44:21This is just an alternative way of doing it
    • 0:44:23that I'm showing you for sake of demonstration
    • 0:44:25where we say when we click anywhere in the document,
    • 0:44:27figure out what was clicked on and save it inside of this variable.
    • 0:44:30And if it's a Hide button, then it's going to have a class of hide,
    • 0:44:35because I gave every Hide button a class of hide.
    • 0:44:39And so what I can say is if element.className equals hide, well,
    • 0:44:47that means that what was clicked on is something with the class of hide,
    • 0:44:50we can assume that it is in fact a Hide button.
    • 0:44:52And then what I want to do is I can do something like element.remove
    • 0:44:56to say go ahead and get rid of that element.
    • 0:45:00So now what does this do?
    • 0:45:01If I refresh the page--
    • 0:45:03let's try it.
    • 0:45:04Post #1.
    • 0:45:04If I hide it, I want to hide Post #1.
    • 0:45:07All right, that didn't quite work.
    • 0:45:08It was close-- it got rid of the Hide button.
    • 0:45:10But I didn't want to get rid of the Hide button,
    • 0:45:12I wanted to get rid of the whole post.
    • 0:45:14So what's going on here is it seems to be that if the element's class name is
    • 0:45:18hide, meaning I clicked on a Hide button,
    • 0:45:20element.remove just removes that element.
    • 0:45:23It removes the Hide button, but it doesn't
    • 0:45:26remove the post that contains it.
    • 0:45:28And if you think about this in terms of the DOM, the post is a div
    • 0:45:31and its child element is the button, this Hide button.
    • 0:45:35And so you remove the button, but it doesn't also remove the post as well.
    • 0:45:39If you want to remove the post as well, you
    • 0:45:41need to remove not the element, but the element's parent.
    • 0:45:44And in JavaScript, it turns out there's a way to do that, too.
    • 0:45:46Rather than element.remove, I can say element.parentElement.remove to say
    • 0:45:52take the element, get its parent, and remove that.
    • 0:45:56So now I refresh the page.
    • 0:45:58Now I see a Post #1.
    • 0:46:00I want to hide it.
    • 0:46:01I hide Post #1 and all right, now I see Post #2 and Post #1 has gone away.
    • 0:46:05If I want to hide Post #3, I hide Post #3.
    • 0:46:08Now Post #3 is gone.
    • 0:46:09Now I go straight from Post #2 Post #4.
    • 0:46:12So this works, but it's also not immediately obvious what's going on.
    • 0:46:16Because all of the posts are the exact same height, when I get rid
    • 0:46:19of Posts 1 and 3, it's not immediately obvious to the eye
    • 0:46:22that they've gone away because Posts 2 and 4,
    • 0:46:25they look almost exactly the same.
    • 0:46:26You really have to be paying attention to know that the hiding worked.
    • 0:46:30And so this can be a time where animation can actually
    • 0:46:32be quite helpful.
    • 0:46:34So what I can do is say something like, let's go ahead
    • 0:46:38and give this post an animation associated with every post.
    • 0:46:43We'll give it an animation-name called hide,
    • 0:46:46an animation-duration of 2 seconds-- we'll say it'll take you 2 seconds
    • 0:46:49in order to hide--
    • 0:46:51and an animation-fill-mode of forwards, I
    • 0:46:53want to go forwards with the animation.
    • 0:46:55And initially, I'll give the post an animation-play-state of paused, meaning
    • 0:47:00initially, I don't want the animation to be running, because I don't
    • 0:47:03want to hide all the posts immediately.
    • 0:47:05Pause this animation.
    • 0:47:06Later, we'll go ahead and run the animation
    • 0:47:09in order to actually hide the post.
    • 0:47:12Then I need to define, what does it actually mean to hide the post?
    • 0:47:16And I'll say, well, all right, at the 0% mark, what does it mean?
    • 0:47:19Let's give yourselves an opacity of 1.
    • 0:47:21Opacity is a CSS property that just controls how opaque
    • 0:47:25or how transparent an HTML element happens to be.
    • 0:47:28And at the end, 100% of the way done with the animation,
    • 0:47:31we'll set opacity to 0.
    • 0:47:33So initially, we can fully see the element.
    • 0:47:35At the end, the element is totally transparent.
    • 0:47:38And now what I need to do is actually trigger this to happen somehow.
    • 0:47:43So this is probably going to happen inside of my event listener.
    • 0:47:47We're-- instead of removing the element right away,
    • 0:47:50let me just take the parentElement and set its animationPlayState equal
    • 0:47:55to running, for example, meaning when I click the Hide button,
    • 0:48:01go ahead and run the animation that will change the opacity from 1 to 0 over
    • 0:48:06the course of a couple of seconds.
    • 0:48:08And then if I really want to, I can add another event listener
    • 0:48:11to say take the parentElement, addEventListener.
    • 0:48:15There's an event called animationend, which
    • 0:48:19happens when the animation is over.
    • 0:48:21And then I can say, all right, when the animation is over,
    • 0:48:24we'll then go ahead and remove the element.
    • 0:48:29So all in all, rather than just immediately remove the element when I
    • 0:48:32click on the button that says Hide, what I'd like to do is say if you click
    • 0:48:36on a button and the button is Hide, go ahead and get the parent element--
    • 0:48:39not the Hide button, but the post itself--
    • 0:48:42set its animationPlayState to running, meaning run the hide animation,
    • 0:48:46and then add an event listener to the parent, to that post as a whole,
    • 0:48:50to say when the animation is over, go ahead and remove that entire post
    • 0:48:54from the DOM altogether.
    • 0:48:56So what is the effect of all of this now, of having this animation
    • 0:48:59and running it?
    • 0:49:01Well, now if I refresh the page, I see all these posts.
    • 0:49:04If I try and hide, like, Post #2, for example, you'll
    • 0:49:07see that the opacity changes and then it slowly disappears.
    • 0:49:11And then only after it's totally transparent,
    • 0:49:13the post disappears entirely.
    • 0:49:15So I can say hide Post #4, it disappears, and then Post #5
    • 0:49:19jumps up to fill its place.
    • 0:49:20And I can do that for any of these posts,
    • 0:49:22triggering the animation when I click on the Hide button.
    • 0:49:25And so this is part of the value of what animation can do,
    • 0:49:28is to be able to make our user interfaces a little more
    • 0:49:31pleasant from the perspective of the user
    • 0:49:33by not immediately getting rid of a post, but by having a nice fadeout
    • 0:49:36so it disappears nicely.
    • 0:49:38Now, even this is not perfect animation wise.
    • 0:49:40Like, one thing you might notice is that it
    • 0:49:42jumps up as soon as the post is gone.
    • 0:49:44If I hide Post #3, I hide it, it disappears, and Post #5
    • 0:49:48sort of jumps up very abruptly in order to fill its place.
    • 0:49:51What I might like is to be a little bit cleverer, to somehow shrink
    • 0:49:55the size of the post after it's gone so that the post doesn't jump into place
    • 0:49:59but it slides a little bit more naturally into place.
    • 0:50:02And so there's some additional things I can play with here.
    • 0:50:04Maybe I want to say that, all right, let me make this animation a multiple part
    • 0:50:09animation.
    • 0:50:10So here, instead of just from 0% to 100% setting the opacity from 1 to 0,
    • 0:50:15maybe in the first 75% of the animation, that
    • 0:50:18will take care of reducing the opacity, going down from 1 all the way down
    • 0:50:22to 0.
    • 0:50:22But in the last 25% of the animation, we'll still end with an opacity of 0,
    • 0:50:28but anything that creates vertical space, I want to reduce down to 0.
    • 0:50:33So the height should be 0 pixels, the line-height,
    • 0:50:36which is how high the text is, should also be 0 pixels.
    • 0:50:39And any padding I want to go away.
    • 0:50:41It turns out I've added some margin to the bottom of the post--
    • 0:50:44I want to make that go away as well.
    • 0:50:46So I want to set all of those to 0 from whatever their initial values happen
    • 0:50:49to be, that initially the height is like 100% of what the height could be.
    • 0:50:53Likewise for line-height, 100% of the parent.
    • 0:50:56Initially I have, like, 20 pixels of padding
    • 0:50:58and a margin at the bottom of 10 pixels.
    • 0:51:01And I want all of that to still be true 75% of the way through the animation.
    • 0:51:07But it's only in the last 25% of the animation
    • 0:51:09that I want to set all of these vertical height properties down to 0.
    • 0:51:12I want to remove all the height, remove the line-height,
    • 0:51:14remove all the padding.
    • 0:51:15And the effect of this is I'll have an animation now where
    • 0:51:18for the first 75% of the animation, the only thing that changes is the opacity.
    • 0:51:23The opacity goes from 1, fully visible, to 0, fully transparent.
    • 0:51:28And then in the last 25% of the animation,
    • 0:51:30the post is already transparent.
    • 0:51:32You can't see it, but it's still taking up physical space on the page.
    • 0:51:36But we're going to now reduce the height of that post
    • 0:51:38so that now you won't be able to see it at all.
    • 0:51:42So now if I refresh this page, here again are all the posts.
    • 0:51:45But now if I click Hide on a particular post,
    • 0:51:48we'll see that it first fades out, and then its height
    • 0:51:50shrinks so that the next post slides very nicely into place.
    • 0:51:54I can do that again.
    • 0:51:55Hide the post, it's transparent, and then it slides into place.
    • 0:51:58And this, again, is just an application of this idea of CSS animations,
    • 0:52:02using properties of animation to make our interfaces a little bit
    • 0:52:06nicer to use, a little bit clearer visually to the user
    • 0:52:09that one post has gone away and the rest of the posts
    • 0:52:11have now scrolled up in order to take their place.
    • 0:52:15So now we've been able to use JavaScript to create
    • 0:52:18a lot of nice user interfaces.
    • 0:52:19We've been able to create a single-page applications,
    • 0:52:21to create infinite scrolling, to be able to create some animations as well
    • 0:52:25and use JavaScript to be able to control them.
    • 0:52:27But one thing you might be realizing at this point
    • 0:52:29is that our applications are starting to get fairly complicated.
    • 0:52:32There's a lot of JavaScript code needed to manipulate
    • 0:52:34a lot of different parts of our application at the same time.
    • 0:52:37And you can imagine that as web pages start to get more complex
    • 0:52:40and as you want to start making them more interactive and more dynamic,
    • 0:52:43there's going to be a lot of JavaScript code required in order to keep
    • 0:52:46everything in sync, in order to make sure that all of the elements
    • 0:52:49are updated when they should, so on and so forth.
    • 0:52:52And it's for that reason that in recent years, a lot of JavaScript
    • 0:52:55has now turned to some JavaScript libraries or frameworks that
    • 0:52:58allow to more efficiently and more effectively
    • 0:53:00create user interfaces that are more interactive and more reactive.
    • 0:53:05And one of the most popular of these is a framework known as React.
    • 0:53:08React is a JavaScript library that is going
    • 0:53:10to enable us to be able to design user interfaces that
    • 0:53:14are very interactive, where the content of the web page updates
    • 0:53:17automatically based on some underlying state.
    • 0:53:20And what we'll do now is take a look at a brief taste of React
    • 0:53:23to get a sense for how frameworks like it can actually work
    • 0:53:26and can help us in designing some interactive and useful interfaces
    • 0:53:29for users to be able to interact with.
    • 0:53:31React is ultimately based on this idea of declarative programming,
    • 0:53:35a particular style of programming which is
    • 0:53:37different from the types of programming you
    • 0:53:39might be familiar with-- more classical programming styles like imperative
    • 0:53:43programming.
    • 0:53:44In imperative programming, you generally give the computer commands,
    • 0:53:47tell the computer what to do.
    • 0:53:49For example, if we had that counter program from before
    • 0:53:52and we wanted to update the counter from one number to another number,
    • 0:53:55in the view, like the HTML that the user sees,
    • 0:53:58we would include something like a heading that
    • 0:54:00just has the number 0 inside of it.
    • 0:54:02And then the logic in imperative programming
    • 0:54:05would take something like this form.
    • 0:54:06It would be like, all right, first document.querySelector("h1") to get
    • 0:54:10that h1 tag.
    • 0:54:12Get it, it's in our HTML.
    • 0:54:13parseInt-- we'll take the string and convert it into an integer,
    • 0:54:16and we can save that inside of a variable called num, for example.
    • 0:54:20And then after that, if I want to increase it,
    • 0:54:22I would take this variable num and just add 1 to it-- num plus equals 1,
    • 0:54:26add 1 to it.
    • 0:54:27And then if I want to update this heading in order to replace the 0 with
    • 0:54:30a 1, for example, well, then I would need to say
    • 0:54:33document.querySelector("h1"), set the inner HTML equal to that number,
    • 0:54:37for instance, in order to say, all right, num is now 1.
    • 0:54:40Go ahead and replace that in the view.
    • 0:54:43But this is a fair amount of code to do something fairly simple,
    • 0:54:46just like increase a number by 1.
    • 0:54:48And the reason why is because we've had to be
    • 0:54:50very explicit about what instructions we're giving to the web browser.
    • 0:54:53We're saying first, grab the h1, figure out what number is inside of it,
    • 0:54:57add 1 to that number, and then replace it inside of this tag.
    • 0:55:01What declarative programming is going to allow us to do
    • 0:55:03is it's going to allow us to just describe what state should
    • 0:55:07be displayed on the page in what form.
    • 0:55:09In declarative programming, in our view, like the HTML-like code
    • 0:55:12that we're going to be writing, we're just
    • 0:55:14going to say something like, h1, and then in curly braces num,
    • 0:55:18to mean fill in the number here.
    • 0:55:21And this is what the React syntax is going to look like.
    • 0:55:23And then the logic code, if we want to increment that number by 1,
    • 0:55:27is we just need to say num plus equals 1.
    • 0:55:30Add 1 to the number.
    • 0:55:31And the effect of that is that since we have declared that inside of this
    • 0:55:35heading, it should be whatever the value of the number
    • 0:55:37is, when we increment the value of number,
    • 0:55:40React is effectively just going to update the view so
    • 0:55:43that the number updates as well.
    • 0:55:45And so this will be some of the power that React gives us.
    • 0:55:48React lets us divide our application into a whole bunch
    • 0:55:51of different components, where a component is something
    • 0:55:54like this thing here that is keeping track
    • 0:55:55of some sort of count, along with a button that might manipulate
    • 0:55:58it, and then make that component based on some underlying state,
    • 0:56:01some underlying variables that represent the state of the application--
    • 0:56:05something like the current number.
    • 0:56:07And then we can manipulate that state, and when we manipulate the state,
    • 0:56:10that will have an impact on what the user actually sees,
    • 0:56:12and React will handle the process of updating that user interface for us.
    • 0:56:17There are a number of ways to get React working on our web page,
    • 0:56:20but the simplest is probably just to include these three JavaScript
    • 0:56:23packages inside of our web page.
    • 0:56:27So we're first going to include React itself,
    • 0:56:29which is going to be the library that's going to allow us to define
    • 0:56:31these components and how they behave.
    • 0:56:33Then it's ReactDOM, a special package that's
    • 0:56:36going to allow us to take React components
    • 0:56:38and insert them into the DOM, the document
    • 0:56:41object model that represents the structure of the entire page.
    • 0:56:44And then finally, Babel is going to be a package
    • 0:56:47that we're going to use in order to translate code
    • 0:56:49from one language to another.
    • 0:56:51It turns out that when we're writing React code,
    • 0:56:53we're not actually going to be writing JavaScript.
    • 0:56:56We're going to be writing in an extension to JavaScript known as JSX.
    • 0:57:00And JSX is going to be an extension to JavaScript that
    • 0:57:03looks a lot like JavaScript, but has some additional features.
    • 0:57:06In particular, it has the ability to effectively allow
    • 0:57:09us to represent HTML inside of our JavaScript code
    • 0:57:12in a way that's much easier to read and it's
    • 0:57:14going to be convenient for us to deal with.
    • 0:57:16Browsers, on the other hand, don't understand JSX automatically,
    • 0:57:20so what we're going to use is a tool like Babel
    • 0:57:22to convert that code into plain JavaScript
    • 0:57:25that our web browsers are ultimately going to be able to understand.
    • 0:57:29The best way to get a feel for this kind of thing is just to see it in action.
    • 0:57:32So I'll go ahead and create a couple of React applications,
    • 0:57:35just to get a sense for how it is that you can use
    • 0:57:37React in your own applications as well.
    • 0:57:40So let's start by taking a look at react.html.
    • 0:57:43And what I have here is the beginning of an HTML page.
    • 0:57:47Inside the head section, what you'll notice
    • 0:57:48is I've already included these three script tags.
    • 0:57:52And what these script tags are doing are just
    • 0:57:53including those three JavaScript libraries
    • 0:57:56we were talking about a moment ago.
    • 0:57:58I have a title for the page just called React.
    • 0:58:00And now let's start to fill in the body of this web page.
    • 0:58:04I'll begin by adding a div, which I'll give an ID to.
    • 0:58:07I'll call it app, but I could call it anything.
    • 0:58:09And this is where our application is going to go.
    • 0:58:12But right now I'm just going to leave it as empty.
    • 0:58:14It's going to be React's job to fill in this div with the content of our user
    • 0:58:19interface.
    • 0:58:20And now beneath that div, I'll start to write some JavaScript.
    • 0:58:23But remember, I'm not going to be writing JavaScript, per se, but rather
    • 0:58:26JSX, that extension to JavaScript.
    • 0:58:29So in this case, I'll need to add an extra attribute. type="text/babel",
    • 0:58:34and all this is doing is telling my browser that it's going to need
    • 0:58:37to translate this JSX code into JavaScript code that the browser is
    • 0:58:41actually going to be able to understand before it tries to run this code.
    • 0:58:45In practice, if you were developing a real application, what
    • 0:58:48you would want to do is you would want to do this translation ahead of time,
    • 0:58:51prior to deploying the application.
    • 0:58:53But here we're just going to translate it on the fly.
    • 0:58:57And so all of our React applications are going
    • 0:58:59to be composed of components, where a component is just some part of my web
    • 0:59:04application's user interface.
    • 0:59:06And to describe a component, I can write a JavaScript function.
    • 0:59:10So I'll create a function called App, which is
    • 0:59:12going to represent this app component.
    • 0:59:15And what's going to go inside of this app component?
    • 0:59:17Well, it's a function, so it's going to return something.
    • 0:59:20And what it's going to return is what should appear inside of that component.
    • 0:59:25And this app component could really just be, for example, a div
    • 0:59:29that says "Hello!", let's say.
    • 0:59:31And this is where the power of JSX really
    • 0:59:34starts to come in, that here I can write HTML-like syntax
    • 0:59:38inside of my JavaScript code, and JSX is going to be able to understand it.
    • 0:59:43So this function right here is a function called
    • 0:59:45App that is representing a React component,
    • 0:59:48and when this component is rendered onto my web page, it's going to say "Hello!"
    • 0:59:53So there's one last line I need inside of my JavaScript now,
    • 0:59:56and that is to actually render this component into the page.
    • 1:00:00To do that, I'll say ReactDOM.render, and the first argument
    • 1:00:05to this function, ReactDOM.render, is what component would I like to render?
    • 1:00:09The component is this app component that I just created.
    • 1:00:13And so I'll say App, again using this HTML-like syntax.
    • 1:00:17And then the second argument is, where on the page
    • 1:00:20would I like to render this component?
    • 1:00:22And I want to render this component right here on line 10, where
    • 1:00:26I have a div whose ID is app.
    • 1:00:28So I'll need to add some JavaScript code to find that particular div.
    • 1:00:32And to do that, I can just say document.querySelector and then
    • 1:00:39#app to say find the element with an ID of app,
    • 1:00:44and that is where I would like to render this app component.
    • 1:00:48So I first created this empty div, then I defined this function
    • 1:00:52representing a React component.
    • 1:00:54And then after that, we're going to render that component
    • 1:00:57inside of the HTML page itself.
    • 1:01:00So now if we were to open a browser and see what this page actually
    • 1:01:04looks like--
    • 1:01:05I'll make the text a little bit bigger--
    • 1:01:07you see that we actually do see the word "Hello!"
    • 1:01:10And if I make a change to the component and refresh the page,
    • 1:01:13it will change the page as well.
    • 1:01:15So if the component instead displayed "Hello, world!",
    • 1:01:19well, then I refresh the page and the page now also says "Hello, world!"
    • 1:01:24And because this is JavaScript, I can add JavaScript code to the function
    • 1:01:28just as I could with any function in JavaScript.
    • 1:01:30Imagine, for example, that I had some variables like--
    • 1:01:34let's create a variable x, which is equal to 1,
    • 1:01:36and a variable y, which is equal to 2.
    • 1:01:39Inside of this div, rather than just render some text,
    • 1:01:42I can use curly braces to say plug in the value of some JavaScript
    • 1:01:46expression.
    • 1:01:47I could plug in the value of x plus y, for example,
    • 1:01:51and now by including x plus y in these curly braces,
    • 1:01:55JavaScript is going to evaluate what is x plus y
    • 1:01:57and display that inside of the div instead.
    • 1:02:01And so now when I refresh the page, you see
    • 1:02:03that the page just says 3, for example.
    • 1:02:07And so that's the basics of React.
    • 1:02:09We create these components and then render those components,
    • 1:02:12all using the power of JavaScript.
    • 1:02:15But where React starts to get more powerful
    • 1:02:17is when we can reuse components.
    • 1:02:19The whole idea of a component is it represents some part of the user
    • 1:02:22interface, and I could reuse that same component
    • 1:02:25across multiple parts of the interface as well.
    • 1:02:28Imagine, for example, that inside of my app component,
    • 1:02:31I was going to render a div that had three headings, each of which
    • 1:02:37said "Hello!"
    • 1:02:39So there's one heading, there's another one,
    • 1:02:42and we'll add a third one there as well.
    • 1:02:45So I have a div with three headings inside of it,
    • 1:02:48and we can see what that looks like.
    • 1:02:49Each one of them says "Hello!"
    • 1:02:51But there's some repetition here.
    • 1:02:52I'm having to use this h1 tag three times,
    • 1:02:55all to create exactly the same UI element on the page.
    • 1:02:59This is a case where I can create a separate component
    • 1:03:02and then just reuse that component, rather than have
    • 1:03:04to repeat myself multiple times.
    • 1:03:07So how could I do that?
    • 1:03:08Well, remember that in JavaScript, we can write a function
    • 1:03:11to represent a React component.
    • 1:03:13So I'll add another function here and I'll
    • 1:03:15call that function Hello, because it's going
    • 1:03:18to represent this hello component.
    • 1:03:20And this Hello function is also going to return something,
    • 1:03:23and what it's going to return is a heading, an h1, that just says "Hello!"
    • 1:03:30And so now inside of my app component, rather than render three separate h1s,
    • 1:03:36I can simplify this a little bit to just say "Hello."
    • 1:03:40Here, I'm saying, go ahead and render a hello component here,
    • 1:03:43render a second one and a third one after that.
    • 1:03:47Each time I render a hello component, it's
    • 1:03:49going to display as this heading that just says "Hello."
    • 1:03:54So I refresh the page and nothing changes.
    • 1:03:56I still see three headings, each of which says "Hello!"
    • 1:03:59because inside of my app component, I'm rendering this hello component
    • 1:04:02three times and each time, it's going to display this h1.
    • 1:04:07But where components start to get more powerful
    • 1:04:09is when they're not always displaying the same information every time,
    • 1:04:13but when we can parameterize those components with properties.
    • 1:04:17Or as React simplifies them, props, short for properties.
    • 1:04:21So what would that mean?
    • 1:04:22We see that HTML elements can take attributes.
    • 1:04:25Likewise, React components can take properties, where maybe I don't just
    • 1:04:28want to say hello, but I want to say hello to someone-- hello to Harry
    • 1:04:32or to Ron or Hermione, for example.
    • 1:04:35So I could say Hello name="Harry", using syntax much like an HTML attribute,
    • 1:04:42then here I say Hello name="Ron", and then finally Hello name="Hermione".
    • 1:04:49And so now my hello component is accepting this prop,
    • 1:04:52this property called name, which is different for all three
    • 1:04:57of these components.
    • 1:04:59And so inside this Hello function now, I would like the Hello function
    • 1:05:03to take advantage of these properties, of these props.
    • 1:05:06And so I'm going to add an argument to the Hello function.
    • 1:05:09That argument is conventionally just called props.
    • 1:05:12And now, instead of just saying Hello, I'm going to say Hello comma.
    • 1:05:16And then remember, to plug in a JavaScript value, I use curly braces.
    • 1:05:20And inside of those curly braces, I can say props dot and then
    • 1:05:25whatever the name of the property is.
    • 1:05:27In this case, the name of the property is just name.
    • 1:05:30So I can say props.name to say whatever the name prop is,
    • 1:05:34go ahead and plug that in right here inside of the hello component.
    • 1:05:38So the hello component is going to say Hello comma, and then someone's name.
    • 1:05:43So I can save that, refresh the page.
    • 1:05:46And now I see "Hello, Harry!", "Hello, Ron!", and "Hello, Hermione!"--
    • 1:05:49three different components, each of which
    • 1:05:51is still just this hello component, but we're
    • 1:05:53rendering it with different props, one time with the name of Harry,
    • 1:05:57one time with the name of Ron, and one time with the name Hermione.
    • 1:06:01And so this is where components can start to get a little bit different.
    • 1:06:04By passing in different props into those components,
    • 1:06:07we can decide how that component is ultimately going to render.
    • 1:06:11But let's add to this a little bit and start to add state
    • 1:06:14into our React components as well.
    • 1:06:16And state is going to mean any kind of data
    • 1:06:19that we want to store inside of the component itself.
    • 1:06:22And for this, let's try to recreate the counter application
    • 1:06:25that we created when we first introduced JavaScript, where we were really
    • 1:06:29just creating a button that allowed you to count,
    • 1:06:31and it counted up from 0, 1, 2, 3, 4, et cetera.
    • 1:06:35So to do this, let's create a new file.
    • 1:06:37I'll create a new file and just call it counter.html.
    • 1:06:41And we can start just by copying the contents of react.html
    • 1:06:45into our counter.html file.
    • 1:06:47We're still going to use the same script tags
    • 1:06:49and we can still have an app component, but what's
    • 1:06:53going to be inside this app component is going to be a little different.
    • 1:06:56I'll change the title of the page to be Counter instead of React.
    • 1:07:02So what goes inside of the app component?
    • 1:07:04Well, if we're going to do this counting,
    • 1:07:06we need a div that's going to display the number that we've currently counted
    • 1:07:09to, something like 0 to start with.
    • 1:07:12And we're going to need a button.
    • 1:07:14This button is just going to be Count, which
    • 1:07:17will be the label for that button.
    • 1:07:19So a div that just says 0 and a button that says Count.
    • 1:07:24And now if I open up counter.html--
    • 1:07:28I'll make it a little bigger--
    • 1:07:29you can see that I have this number 0 here and a button that says Count.
    • 1:07:34Of course, right now, clicking on the button
    • 1:07:36doesn't do anything because I haven't written any JavaScript
    • 1:07:38code to say what should happen when this button is actually clicked on.
    • 1:07:43But before we get there, let's modify this program a little bit.
    • 1:07:48Right now, I've written the number 0 directly into the div itself,
    • 1:07:51but it's not always going to be 0.
    • 1:07:53Eventually, as I start counting by pressing that Count button,
    • 1:07:56that number is going to change.
    • 1:07:58So what I'm going to do now is factor this 0 out
    • 1:08:01into what's known as state inside of my React component.
    • 1:08:05And here, one way to create state in my React component
    • 1:08:08is to use a special function inside of React called useState.
    • 1:08:13This is one example of a React hook that allows
    • 1:08:16me to add some additional functionality into my React component.
    • 1:08:20And the argument to React.useState is going
    • 1:08:23to be the initial value of that state.
    • 1:08:25I'm going to start counting and I want to start counting from the number 0,
    • 1:08:28so I'm going to include the number 0 as the argument to this useState function.
    • 1:08:34So we're going to start counting at 0.
    • 1:08:36And what this useState function returns is really an array of two things.
    • 1:08:41It's going to be a variable that I can give a name to--
    • 1:08:45I'll call it count--
    • 1:08:46and also a function that I'm going to call setCount.
    • 1:08:49And that function is going to allow me to set the value for the state,
    • 1:08:53if ever I need to change the state at some point in the future.
    • 1:08:57So this useState function accepts 0, the initial state, as its argument.
    • 1:09:02And then I get two things back.
    • 1:09:04I get the state variable itself, called count,
    • 1:09:07and I get a function for changing that state when I need to.
    • 1:09:10So now instead of rendering a 0 inside of the div
    • 1:09:13just by writing the number 0, I'm going to instead in curly braces
    • 1:09:18go ahead and render whatever the value of count is.
    • 1:09:21Initially, it's going to be 0, but eventually, that number might change,
    • 1:09:24and I want my UI to reflect the changes in the underlying state.
    • 1:09:29So right now if I refresh the page, it still says 0,
    • 1:09:32because the initial state was set to 0, but I could change that.
    • 1:09:35If initially that initial state was some other value, I could refresh the page
    • 1:09:39and see a different value appear for the count instead.
    • 1:09:43Whatever the value of this count variable is in the state,
    • 1:09:46that's going to be what the user is going
    • 1:09:48to see when they're looking at my user interface
    • 1:09:51and when they see my component.
    • 1:09:54So now let's make this button actually do
    • 1:09:56something, because right now, the number is never changing.
    • 1:09:59To do that, I can add an onClick handler.
    • 1:10:02And notice one difference between onClick in React
    • 1:10:05and onclick as we traditionally used it in JavaScript--
    • 1:10:07I'm using this capital C, and that's just a common React convention
    • 1:10:11when we're defining event handlers.
    • 1:10:14And here, I'm going to say onClick, and then in curly braces
    • 1:10:17the name of a function-- a function that I would like
    • 1:10:20to run when this button is clicked.
    • 1:10:23And I can call that function whatever I'd like.
    • 1:10:25I'll call it updateCount, for example.
    • 1:10:29And now what I need to do is define a function called updateCount.
    • 1:10:34And I'm going to define that function inside of this React component,
    • 1:10:38inside of my app function.
    • 1:10:39It turns out in JavaScript, you can have functions that
    • 1:10:41are defined inside of other functions.
    • 1:10:44So I'll define this function, called updateCount,
    • 1:10:48and what do I want the updateCount function to do?
    • 1:10:51Well, what I'd like to do is just increase count by 1.
    • 1:10:53And you might think that I could do that just
    • 1:10:55by saying count equals count plus 1, but it turns out
    • 1:10:58you can't quite do that in React.
    • 1:11:00In React, whenever I'm using this useState,
    • 1:11:03if I want to change the state, I have to use this function
    • 1:11:07that useState provides to me for whenever I
    • 1:11:10want to set the new value of the state.
    • 1:11:13So rather than count equals count plus 1, I have to use the setCount function,
    • 1:11:18and the argument to setCount is going to be count plus 1.
    • 1:11:22So setCount is this function that is going to change the underlying state
    • 1:11:26inside of my component, and the argument is what should the new state be.
    • 1:11:30And in this case, it's just going to be count plus 1,
    • 1:11:33one more than whatever the count was before.
    • 1:11:37So I can save that.
    • 1:11:39And I'll go ahead and refresh the page.
    • 1:11:40It starts at a 0, but every time I click on this Count button,
    • 1:11:44you'll notice the count increases by one.
    • 1:11:48And again, I have no code that's saying go into the div and change whatever
    • 1:11:52is inside of the div.
    • 1:11:53All I have inside of this div is this reference to this state variable count.
    • 1:11:57And whenever the state changes, JavaScript and in turn React
    • 1:12:02knows that what React needs to do is to recreate this component,
    • 1:12:05rerender the component by displaying the new value of this state variable.
    • 1:12:10And then when the button is clicked on, we're
    • 1:12:12able to run this function to change the value of that underlying state.
    • 1:12:17So by taking advantage of these React components with state,
    • 1:12:19we can start to represent information inside of our components
    • 1:12:22and then define what our component is going to display as,
    • 1:12:26just by representing HTML in terms of that underlying state,
    • 1:12:29deciding how we should use that state in order
    • 1:12:32to render an interface that the user is ultimately going to see.
    • 1:12:37So let's now try and put these pieces together
    • 1:12:39and create a web application that uses these abilities of React
    • 1:12:43to define state and to manipulate that state and in turn,
    • 1:12:47update a user interface based on changes that
    • 1:12:49are happening to that underlying state.
    • 1:12:52And we'll create an application that will just
    • 1:12:54display some simple mathematical questions to the user
    • 1:12:57and quiz the user on some basic addition facts, for example.
    • 1:13:01So let's create that application.
    • 1:13:02I'll create a new file and call it addition.html.
    • 1:13:07And inside of addition.html, I'll start again
    • 1:13:10just by copying the contents of this counter.html file,
    • 1:13:14because the framework, the structure of this page will be similar.
    • 1:13:18But I'll go ahead and clear out what's inside of my app component,
    • 1:13:22at least for now.
    • 1:13:24And so what would I like for my app component to render?
    • 1:13:28Well, let's go ahead and render a div.
    • 1:13:30And if I want to create an application that's
    • 1:13:32going to ask the user some mathematical questions
    • 1:13:35and then prompt the user to type in an answer,
    • 1:13:38there are at least two parts of this user interface that I'm going to need.
    • 1:13:41I'm going to need a place to display the addition fact answer, like what
    • 1:13:45is 1 plus 2, for example.
    • 1:13:47And then I'll need an input field where the user can type in their response
    • 1:13:50to that question and then see if they got the question right or wrong.
    • 1:13:55So inside the div, I'll start by creating
    • 1:13:57a div that displays the question itself, something like 1 plus 2.
    • 1:14:02And then beneath that, I'll just add an input field.
    • 1:14:05Eventually, we'll add more to this user interface, but for now,
    • 1:14:08all we really need is a div that displays
    • 1:14:10the mathematical question and an input for the user to type in their response.
    • 1:14:15So now if I go ahead and go to addition.html, here's what I see.
    • 1:14:19I'll make it a little bit bigger.
    • 1:14:21I see 1 plus 2, and then an input field where the user
    • 1:14:25could start to type in their response.
    • 1:14:27But just as we did before, I don't want to literally write the numbers
    • 1:14:311 and 2 into what I'm returning.
    • 1:14:34Instead, I want these 1 and 2 to be based on some underlying state
    • 1:14:38inside of my application.
    • 1:14:39The application is going to maintain state
    • 1:14:41about what two numbers to add together, and then it's
    • 1:14:44going to display a user interface based on that state.
    • 1:14:47So what could I do here?
    • 1:14:49Well, one thing I could do is again use React.useState, start this number off
    • 1:14:54as 1, and maybe call this num1 and then a function to set number 1.
    • 1:15:01And then I could do it again.
    • 1:15:02Let's create num2 and set num2 to be React.useState(2).
    • 1:15:07And I could have two different pieces of state, num1 and num2, each of which
    • 1:15:11has a different function, setNum1 and setNum2, that
    • 1:15:14are each representing the two different numbers that I
    • 1:15:16would like to add together.
    • 1:15:18But already this is starting to get messy and over time,
    • 1:15:21as I add more different pieces of state to the application--
    • 1:15:24as we'll see in just a moment--
    • 1:15:25the state might start to get more and more complex,
    • 1:15:27with more and more different functions and variables.
    • 1:15:29So it's often helpful, and a common practice in React,
    • 1:15:32to combine multiple pieces of state just into one JavaScript object that's
    • 1:15:37maintaining all of the different pieces of state for this particular component.
    • 1:15:42And to do that, I'll again use React.useState.
    • 1:15:46But instead of setting the state initially to be a number like 1 or 2,
    • 1:15:50it's instead going to be a JavaScript object that
    • 1:15:53has keys and values, where I could say let num1 be the number 1
    • 1:15:58and let num2 be the number 2.
    • 1:16:01Much like a dictionary in Python, for example,
    • 1:16:04where I have multiple different values, num1 and num2, all together
    • 1:16:08inside of the same object.
    • 1:16:10And I can call that state and have a variable--
    • 1:16:12and have a function called setState that is going
    • 1:16:15to update the value of that state.
    • 1:16:17And so rather than have to have all of these different variables,
    • 1:16:21I can simplify a little bit to just state and a function to set the state,
    • 1:16:25and the state now has these two different pieces, number 1
    • 1:16:28and number 2.
    • 1:16:31And so now instead of rendering literally the number 1,
    • 1:16:34using curly braces I can say state.num1.
    • 1:16:38And instead of rendering literally the number 2,
    • 1:16:40I can say state.num2, drawing upon that state
    • 1:16:45to decide what it is going to appear inside of the user interface.
    • 1:16:49And so right now, the page appears no different.
    • 1:16:51But if I were to change those initial values of the state,
    • 1:16:54maybe make it 2 and 4, for example, and then refresh the page,
    • 1:16:58well, now it displays as 2 plus 4.
    • 1:17:02And so that's helpful.
    • 1:17:03We now have a user interface where the numbers are based on the state.
    • 1:17:07But now what I'd like to do is add the ability
    • 1:17:10to keep track of what the user typed in so we can tell if the user correctly
    • 1:17:13typed in the answer to this mathematical problem.
    • 1:17:16And how would I do that?
    • 1:17:18Well, the state represents any information
    • 1:17:21that we need to keep track of inside of this component.
    • 1:17:24And so in addition to storing the two numbers inside of the state,
    • 1:17:27I likely also need to keep track of a third piece of information,
    • 1:17:31which is the response--
    • 1:17:32what did the user type in into this text field?
    • 1:17:36And so we'll add a third part of the state called response that initially
    • 1:17:40will just be the empty string.
    • 1:17:41It will just be nothing.
    • 1:17:43And then this input field, I'm going to give it a value,
    • 1:17:47and the value is going to be state.response.
    • 1:17:50Whatever the user typed in as the response,
    • 1:17:52that's stored inside of the state, and that
    • 1:17:54is going to be the value of what shows up in the input field.
    • 1:17:59And so that way, whatever is in the input field will have access to it
    • 1:18:01inside of this state.response variable.
    • 1:18:04But there is a problem, and here's the problem.
    • 1:18:07I'll try refreshing the page, I'll go into this text field.
    • 1:18:09And let's say I know the answer.
    • 1:18:11I know 2 plus 4 is equal to 6.
    • 1:18:12I'm now going to press 6 on my keyboard.
    • 1:18:16But as I press 6 on the keyboard, nothing's happening.
    • 1:18:19No 6 is appearing inside of the text field,
    • 1:18:21even though I am pressing the key on the keyboard.
    • 1:18:25So why is that?
    • 1:18:25Why is the text field not updating?
    • 1:18:28Well, the reason is the value of the input field, whatever
    • 1:18:31appears in the input field, is this value, state.response,
    • 1:18:35and state.response is always this empty string
    • 1:18:38and never changing what state.response is equal to.
    • 1:18:42And so I need to change this a little bit.
    • 1:18:45I need to add as an attribute to this input field onChange,
    • 1:18:49meaning when the input field changes, I need to do something.
    • 1:18:52And I'll call a function that I can call updateResponse.
    • 1:18:56But again, I could call that update function whatever I'd like.
    • 1:18:59It's just the name for the function that's
    • 1:19:01going to run whenever something changes in the input field.
    • 1:19:04So let me now define that updateResponse function.
    • 1:19:07I'll define a function called updateResponse.
    • 1:19:10And because it's an event handler, it can accept an argument,
    • 1:19:13which is the event itself--
    • 1:19:15the fact that something has changed inside of the input field.
    • 1:19:19And when I have access to this event, it turns out
    • 1:19:21that if I want to figure out what it is the user has typed into the input
    • 1:19:24field, I can get at that with event.target.value.
    • 1:19:29And I'd only know that by looking at it in the documentation.
    • 1:19:31But what I'd like is for event.target.value
    • 1:19:35to be the new value for this response.
    • 1:19:38And so what I'd like to do is do something like this-- setState.
    • 1:19:42And what should the new value of the state be?
    • 1:19:44Well, I would like for a response to no longer be the empty string,
    • 1:19:48but to now be event.target.value.
    • 1:19:51And that is going to be the new value for response.
    • 1:19:55But I'm not quite done yet, because state doesn't just
    • 1:19:58have response as one of the parts of the state.
    • 1:20:01The state also has num1 and num2, and those two pieces
    • 1:20:05aren't really changing.
    • 1:20:06So I could say, all right, num1 is just going to be whatever state.num1 was.
    • 1:20:11That's not changing.
    • 1:20:12And num2 is going to be whatever state.num2 was.
    • 1:20:14That's not changing.
    • 1:20:16The only thing that's changing is the response.
    • 1:20:19But this is starting to get a little bit verbose,
    • 1:20:21and especially if I start adding more and more different pieces to the state,
    • 1:20:24it's going to become difficult to manage if I constantly
    • 1:20:27have to repeat myself for all of the parts of the state that
    • 1:20:30aren't changing.
    • 1:20:31Ideally, what I'd like to do is just specify
    • 1:20:33the parts of the state that will change and ignore everything else.
    • 1:20:38And so one shorthand way to do that in JavaScript
    • 1:20:41is to use what's known as the spread operator.
    • 1:20:43And it looks like this-- dot dot dot and then state.
    • 1:20:47And what this is saying is just use the existing
    • 1:20:50values of the state for everything else, like num1 and num2.
    • 1:20:53The only thing to override is the new value for the response.
    • 1:20:58And so this syntax here is my way of saying,
    • 1:21:01I would like to update the state.
    • 1:21:02Everything should stay the same except for response,
    • 1:21:06which is now going to be event.target.value--
    • 1:21:09in other words, whatever it is the user typed in into that input field.
    • 1:21:14And so I'll go ahead and refresh the page,
    • 1:21:16and now if I type a number, like 6, you actually
    • 1:21:19see that number appear in the input field.
    • 1:21:22So that's great we've now displayed a question where the numbers are stored
    • 1:21:25in the state, and the user can type in a response where that response is also
    • 1:21:30stored in the state.
    • 1:21:31Now what I'd like is when the user presses the Enter key
    • 1:21:34on their keyboard, we check--
    • 1:21:35did they get the answer right or did they get the answer wrong?
    • 1:21:40And so how would I do that?
    • 1:21:41Well, the first thing I need to do is in this input field,
    • 1:21:45somehow detect when a key is pressed.
    • 1:21:48When a key is pressed, what I'd like to do
    • 1:21:50is check to see if it was the Enter key.
    • 1:21:53And if it was the Enter key, then let's go ahead
    • 1:21:55and check to see what the actual sum of the two numbers is
    • 1:21:58and see if the user got that right or wrong.
    • 1:22:01So let's add an event handler.
    • 1:22:03onKeyPress is going to be equal to something.
    • 1:22:06Again, I can name this function whatever I'd like.
    • 1:22:09I'll call it inputKeyPress, but again, I could name that anything.
    • 1:22:13And now let's define that inputKeyPress function.
    • 1:22:17So up above, I'm going to define this function called inputKeyPress.
    • 1:22:21Again, it takes that event as its argument.
    • 1:22:24And this event is going to happen any time a key is pressed,
    • 1:22:28regardless of whether it's a letter or a number or the Enter key.
    • 1:22:31And so I want to check to make sure that the key is actually the Enter key.
    • 1:22:35That's the only time that I want to now check
    • 1:22:37to see if they got the question right or wrong.
    • 1:22:39So we'll add here a condition.
    • 1:22:41It's just JavaScript, so I can say if event.key
    • 1:22:44is equal to Enter, well, then, let's go ahead and check.
    • 1:22:48And otherwise, we don't have to do anything.
    • 1:22:50I don't need an else case here, because nothing
    • 1:22:52should happen unless it's the Enter key that was actually pressed.
    • 1:22:57And so now how do I check to see if the user got the answer right or wrong?
    • 1:23:03Well, inside of state.num1 is the first number, and inside of state.num2
    • 1:23:08is the second number.
    • 1:23:10So I could have a condition that checked if state.num1 plus state.num2 is
    • 1:23:14equal to state.response, which is what the user typed in into the input field.
    • 1:23:21But that doesn't quite work, because state.response, that's a string.
    • 1:23:26The user doesn't necessarily have to type in numbers.
    • 1:23:28It's possible the user is going to type in some letters
    • 1:23:31instead, for example, or other characters instead.
    • 1:23:34And so what I'm going to do first is convert the response into an integer,
    • 1:23:39if we're able to do so.
    • 1:23:41So I'm going to define a variable called answer using the JavaScript function
    • 1:23:44parseInt that takes a string and tries to convert it into an integer.
    • 1:23:49So we're going to parse the int state.response.
    • 1:23:54And now we can check.
    • 1:23:55If number 1 plus number 2 is equal to the answer,
    • 1:24:00well, then this means the user got the question right.
    • 1:24:05And else if the sum is not equal to the answer,
    • 1:24:08that means the user got the question wrong.
    • 1:24:12And so now what I could do is handle those two different scenarios.
    • 1:24:15In one case, the user got the question right and we should do something,
    • 1:24:19and in another case, the user got the question wrong
    • 1:24:21and we should do something else.
    • 1:24:22And we're making that decision by looking
    • 1:24:25at the state of the application, by looking at what two numbers we're
    • 1:24:28supposed to be adding and looking at what
    • 1:24:30the user typed in as their response.
    • 1:24:33So what should we do when the user gets a question right
    • 1:24:36or gets a question wrong?
    • 1:24:37Well, maybe this game is going to keep score
    • 1:24:39by maintaining a number for how many questions the user has gotten right.
    • 1:24:43And every time the user gets a question right,
    • 1:24:45we could increase that score by 1, and any time
    • 1:24:48the user gets a question wrong, we could decrease that score by 1, for example.
    • 1:24:53So how would we do that?
    • 1:24:54Well, the score is some piece of state inside of the application,
    • 1:24:59and so we're going to need to add to the state.
    • 1:25:01Right now in the state, we're storing the number 1, a number 2,
    • 1:25:04and a response.
    • 1:25:06I'll add to that a score where the score is going to start out as just 0.
    • 1:25:12And we can render that score on the page.
    • 1:25:14If I scroll down to where we're returning the div to render,
    • 1:25:18let's add another div that says the score is,
    • 1:25:23and then using curly braces, plug in whatever the value of state.score is.
    • 1:25:29Whatever the score is, let's figure that out from the state
    • 1:25:32and let's display that in the user interface.
    • 1:25:35So now this user interface shows not only a question
    • 1:25:39and an input field, but also a score.
    • 1:25:41And the score starts out as just the number 0.
    • 1:25:46So let's now go back to this function.
    • 1:25:49When a key is pressed, if it's the Enter key,
    • 1:25:52let's check to see if they got the answer right or wrong.
    • 1:25:54We check-- did the user actually get the question right?
    • 1:25:58If so, what should we do?
    • 1:26:00Well, we should increase the score.
    • 1:26:02And how do we do that?
    • 1:26:03We do that by calling the setState function.
    • 1:26:06All of the state is going to be the same, so using
    • 1:26:08that dot dot dot state spread operator.
    • 1:26:11The only thing that's different is the score
    • 1:26:13is going to be state.score plus 1.
    • 1:26:18So we're updating the state to increase the score by 1.
    • 1:26:22And if the user gets the question wrong, let's set the state
    • 1:26:25to be dot dot dot state, and then the score
    • 1:26:29is going to be state.score minus 1.
    • 1:26:33So if the user gets the question right, we increase the score by 1.
    • 1:26:37Otherwise, we decrease the score by 1.
    • 1:26:39And let's test that to see what it actually looks
    • 1:26:41like when we try this in the user interface.
    • 1:26:44I'll refresh the page--
    • 1:26:462 plus 4.
    • 1:26:47If I type in the correct answer, 6, press Return, the score increases by 1.
    • 1:26:53If I typed in the wrong answer, let's say 8, press Return,
    • 1:26:57the score decreases by 1.
    • 1:26:59So this appears to work.
    • 1:27:00Depending on whether I get the question right or wrong,
    • 1:27:03the score is able to update, increasing or decreasing
    • 1:27:06based on the result of that condition.
    • 1:27:08Now, this game is pretty easy to get a high score on right now, because I
    • 1:27:11can just keep pressing return over and over and over,
    • 1:27:14and the question's never changing.
    • 1:27:16My response is already there.
    • 1:27:17And so the score keeps going up and up and up.
    • 1:27:20So let's make the game a little bit more interesting.
    • 1:27:22Every time the user gets a question right,
    • 1:27:25let's display a new question for them to answer.
    • 1:27:28And how would we do that?
    • 1:27:30Well, the question that's displayed to the user
    • 1:27:32is based on two underlying pieces of the state of the component.
    • 1:27:36It's based on state.num1 and it's based on state.num2.
    • 1:27:41So if I want to change the question, all I have to do
    • 1:27:45is when the user gets the question right and I'm
    • 1:27:47updating the state, instead of only updating the score,
    • 1:27:51let's also update num1 and num2.
    • 1:27:55And I could set these to be specific values,
    • 1:27:58maybe like 5 and 10 for example, but let's make it more interesting
    • 1:28:02and display a random number every time.
    • 1:28:04We'll generate a random number, and so the user
    • 1:28:06will be adding two random numbers together every time they
    • 1:28:09get a new question right.
    • 1:28:11How do we generate a random number?
    • 1:28:12Well, Math.random is a JavaScript function
    • 1:28:15that generates a random number between 0 and 1.
    • 1:28:18We can multiply it by 10, so now we're getting a number between 0 and 10.
    • 1:28:22But we don't want any decimals to appear in the number.
    • 1:28:25So we'll go ahead and take the ceiling of the number, Math.ceil,
    • 1:28:29to say if the number was, like, 5.8, we'll just go ahead and round that up
    • 1:28:33to 6, for example.
    • 1:28:34And we'll do the same thing for number 2.
    • 1:28:36We'll take the ceiling of math.random times 10.
    • 1:28:41So every time the user gets a question right,
    • 1:28:43we'll update num1 and num2 to be new random numbers generated just
    • 1:28:49like this.
    • 1:28:51And so let's go back and try it again.
    • 1:28:54We see 2 plus 4.
    • 1:28:55I type in the correct answer, 6, and the question changes.
    • 1:28:598 plus 5.
    • 1:29:00I type in the correct answer.
    • 1:29:01Press Return.
    • 1:29:02My score increases, and the question changes again.
    • 1:29:05This time if I get the answer wrong--
    • 1:29:06I type in 10, for example--
    • 1:29:08watch my score decrease.
    • 1:29:10It went from 2 down to 1.
    • 1:29:12But the question didn't change.
    • 1:29:13Now I get another opportunity to try to answer this question.
    • 1:29:16And when I answer it correctly, the score increases again from 1 to 2.
    • 1:29:21So this game is starting to come along now.
    • 1:29:23It's keeping track of my score, it's displaying different questions.
    • 1:29:26There is at least one user interface quirk right now,
    • 1:29:29and that is the fact that at the moment, when I get a question right and press
    • 1:29:33Return--
    • 1:29:33I type in 6 and press Return--
    • 1:29:35the 6 still stays there.
    • 1:29:37Ideally, I get a new question.
    • 1:29:38I'd like to clear out the response so the user can just
    • 1:29:41type in whatever the new answer is, rather than have
    • 1:29:44to delete whatever they typed in before and then type in a new number.
    • 1:29:48So how could we do that-- reset whatever is inside of the input field?
    • 1:29:52Well, what's typed into the input field is stored inside
    • 1:29:55of the state of my component.
    • 1:29:57It's stored inside of state.response.
    • 1:30:00And so if I wanted to change that, all I would have to do
    • 1:30:04is say, let's change the response to be the empty string.
    • 1:30:10When the user gets a question right, we're
    • 1:30:12going to update these two numbers, increase the score,
    • 1:30:15and also clear out the response so that it's just the empty string.
    • 1:30:20And I can do the same thing if the user gets a question wrong--
    • 1:30:23decrease the score by 1, but also clear out
    • 1:30:26that response back to the empty string so that there's nothing there.
    • 1:30:31And so now we get a question, I type in an answer, press Return,
    • 1:30:36and the input field clears out, I get a new question,
    • 1:30:39and the score increases by 1.
    • 1:30:41Four separate pieces of state all changing at the same time,
    • 1:30:44and that gets reflected in the user interface that I'm now able to see.
    • 1:30:48So I type in another value and the score increases and everything updates again.
    • 1:30:55All right, so that's definitely progress.
    • 1:30:57One other user interface quirk that I noticed
    • 1:30:59here is that the input field by default isn't automatically selected
    • 1:31:03where I would have to go in and click on the input field
    • 1:31:06in order to highlight it so that I can start typing in my response.
    • 1:31:09I can fix that pretty easily if I scroll down to where the input field is.
    • 1:31:14We'll add an autoFocus attribute and just set
    • 1:31:18that to be true so that the input field automatically focuses when
    • 1:31:22I load the page for the first time.
    • 1:31:25So now I refresh the page.
    • 1:31:26The input field is already highlighted, and immediately I
    • 1:31:29can start to try to play this game.
    • 1:31:32So now that we have the basic functionality of this app working,
    • 1:31:35let's try and improve the CSS so that the game looks a little bit nicer.
    • 1:31:39I'll scroll up to the top of the page and add a style tag
    • 1:31:43to the head section of my HTML page.
    • 1:31:46And I'd like for this entire app to be centered,
    • 1:31:49so I'll say text-align is going to be center.
    • 1:31:52And I'm going to set the font-family to be sans-serif, because I prefer
    • 1:31:57that font for this particular game.
    • 1:32:00So I refresh the page and now everything is centered,
    • 1:32:02and the font is different than what the default was.
    • 1:32:05And what else would I like to have changed?
    • 1:32:08Well, this problem, 2 plus 4, maybe I'd like for that to be bigger.
    • 1:32:11I'd like the problem to be big, and the score
    • 1:32:13beneath that, that can stay the same size that it is right now.
    • 1:32:17So how would I do that?
    • 1:32:19Well, if I go back to the HTML here, I'll
    • 1:32:22go ahead and give this div where I'm displaying
    • 1:32:23the problem, number 1 plus number 2, I'll give it an ID of problem.
    • 1:32:29And then if I scroll back up, I'll say for the element with an ID of problem,
    • 1:32:35let's go ahead and set the font size to be 72 pixels, for example,
    • 1:32:41just to make it bigger.
    • 1:32:42And so now I see a big math equation, 2 plus 4,
    • 1:32:45for example, the input field, and then the smaller score beneath it.
    • 1:32:50So that's a nice UI enhancement a little bit,
    • 1:32:52and now I can play the game, get a question right,
    • 1:32:54and the score increases.
    • 1:32:56I get a question wrong and I get to try again.
    • 1:32:59But maybe I'd like to offer more of a visual indication
    • 1:33:03that the user got a question wrong.
    • 1:33:04Maybe any time the user gets a question wrong,
    • 1:33:07I'd like to change the color of this text.
    • 1:33:09Instead of being black, instead it should be red
    • 1:33:11when the user gets a question wrong.
    • 1:33:14And how could I go about doing that?
    • 1:33:16Well, we can change the color of something just by using CSS.
    • 1:33:19If we had, like, a class called incorrect, for example.
    • 1:33:23If I scroll down here and give this div a class name, which
    • 1:33:29is how you add a class in React, of incorrect,
    • 1:33:34then I could use this class name to style it as red or not red.
    • 1:33:39So I could say anything that has a class of incorrect, let's go ahead
    • 1:33:43and give that a color of red.
    • 1:33:47And so now, because I gave this problem a class of incorrect
    • 1:33:52and I said turn all incorrect text to be red,
    • 1:33:55we now see this text appear as red.
    • 1:33:57But this, again, is not quite what I want.
    • 1:33:59I don't want it to be red all of the time.
    • 1:34:01I only want it to be red when the user has just gotten the question wrong,
    • 1:34:05when they were just incorrect in answering a mathematical question.
    • 1:34:09And so how could I represent that information inside of my application?
    • 1:34:13Well, I'm going to need some additional state.
    • 1:34:15State, again, is any information that I need
    • 1:34:17to keep track of inside of my component.
    • 1:34:20And now it seems that in addition to the response and the score and the numbers,
    • 1:34:24I also want to keep track of did the user just answer a question incorrectly
    • 1:34:29or not?
    • 1:34:30So I'll add another piece to the state.
    • 1:34:32I'll call it incorrect.
    • 1:34:34And initially, it will be false.
    • 1:34:36They didn't just get something incorrect.
    • 1:34:39And now here, if I scroll down to this className,
    • 1:34:43rather than have it be incorrect all the time, let me add in curly braces
    • 1:34:49an expression.
    • 1:34:50I'll say if state.incorrect is true, using the ternary operator
    • 1:34:55with a question mark, then the class should be incorrect.
    • 1:34:59But otherwise, it shouldn't have a class of incorrect.
    • 1:35:02It'll just be the empty string.
    • 1:35:03And so this expression here allows me to change the class of an HTML element
    • 1:35:09based on the underlying state.
    • 1:35:10If state.incorrect is true, then this div will have a class of incorrect,
    • 1:35:15and otherwise, it won't.
    • 1:35:18And so now when I load the page for the first time, the text appears as black.
    • 1:35:23And what I need to do is when the user gets a question wrong,
    • 1:35:26I need to change the state to indicate that they just got a question wrong.
    • 1:35:31How do I do that?
    • 1:35:33Well, here is the setState call when the user gets a question wrong.
    • 1:35:38And in that case, I'll go ahead and set incorrect equal to true.
    • 1:35:43And when the user gets a question right, we'll
    • 1:35:46go ahead and set incorrect equal to false.
    • 1:35:49We're modifying this one additional piece of state
    • 1:35:51based on whether the user got the question right or wrong.
    • 1:35:56So now if I load the page, answer a question correctly,
    • 1:35:59the score increases and I get a new question.
    • 1:36:02But if I answer a question incorrectly and press Return,
    • 1:36:05you'll notice the score decreases, the input field clears out,
    • 1:36:08and the text changes color because I changed
    • 1:36:11the value of that incorrect part of the underlying state and based on that,
    • 1:36:15we were able to see the text color change as well.
    • 1:36:18If I now get a question correct, press Return,
    • 1:36:20the text color changes back to black and the score increases.
    • 1:36:26And let's now add one final piece of state or one final change to the UI
    • 1:36:30for this application.
    • 1:36:31Let's give me a way to win this game.
    • 1:36:33Maybe once I get to a score of 10 by answering 10 questions correctly,
    • 1:36:38then we're going to win the game.
    • 1:36:40And how could I do that?
    • 1:36:41Well, remember that each React component can just be a JavaScript function.
    • 1:36:46And this function is just immediately returning this div,
    • 1:36:49but it's a function, so I can add additional logic to it.
    • 1:36:52I can say if state.score is equal to 10, for example, then
    • 1:36:58rather than render the old div, let's return a new div.
    • 1:37:04This div is just going to display something like "You won!"
    • 1:37:10And so that I can style it, I'll give it an ID.
    • 1:37:13The ID will be winner.
    • 1:37:16And if the ID is winner, let's go ahead and make the font size 72 pixels
    • 1:37:23and let's make the color green if I win.
    • 1:37:26So I added some CSS just to style it, but really, the only new logic
    • 1:37:30is further down below, where I'm here saying check the state.
    • 1:37:34If the score is 10, well, that means we win,
    • 1:37:37so instead of returning the new problem, just
    • 1:37:39return a div that says you won the game.
    • 1:37:43So let's try that now
    • 1:37:45I get these questions.
    • 1:37:46Every time I answer a question, you're noticing that the score
    • 1:37:49is going to increase by 1.
    • 1:37:51And every time we're generating new random numbers
    • 1:37:53to display as what's going to appear in the user interface.
    • 1:37:58And once I get to question number 10, if I answer it correctly, press Return,
    • 1:38:03the entire UI changes.
    • 1:38:04Instead of the problem and an input field and a score,
    • 1:38:07I just see in green large text that I won.
    • 1:38:11And again, I was able to do that by looking here at this condition, where
    • 1:38:15we're looking at the value of the state, and if the state is 10,
    • 1:38:19we're deciding what to render.
    • 1:38:21And this, again, is one of the great powers of React,
    • 1:38:23this ability to use this underlying state
    • 1:38:26and based on the value of the underlying state,
    • 1:38:28decide what it is the user should see in their user interface.
    • 1:38:32And React is just one of many libraries that do this type of thing.
    • 1:38:35Other popular ones include Angular and Vue, where all of these
    • 1:38:38are just these web frameworks that make it easier
    • 1:38:41to be able to create applications that are able to respond
    • 1:38:44to some underlying state so that you, the programmer,
    • 1:38:46don't have to worry about constantly having to manipulate
    • 1:38:49various different parts of the page, especially
    • 1:38:52as you imagine websites like Facebook or Twitter,
    • 1:38:54where there are many things happening on the page at the same time.
    • 1:38:57Every time a new tweet comes in, you might get a notification
    • 1:38:59and see a new post in your main area of your news feed.
    • 1:39:02So these are the types of things that you might want the application
    • 1:39:06to be able to more easily handle for you, where you describe what
    • 1:39:09the state is, you describe what the page should look like based
    • 1:39:12on that underlying state, and let the library,
    • 1:39:14whether it's React or something else, begin to handle
    • 1:39:16the process of doing that for you.
    • 1:39:19And the world of user interfaces is changing pretty quickly--
    • 1:39:22that a lot changes in user interfaces in terms of the technologies
    • 1:39:25and the tools that are quite popular.
    • 1:39:26But they're really based on the same set of underlying ideas,
    • 1:39:29the idea that we can use JavaScript in order to manipulate what it is the user
    • 1:39:33sees on their page, in order to detect what's
    • 1:39:35happening based on particular events, like scrolling
    • 1:39:38to the bottom of the page or typing something into an input field,
    • 1:39:41and then responding to those particular events
    • 1:39:44by providing some sort of function that gets called
    • 1:39:46any time a particular event happens.
    • 1:39:48By mixing that in with other features, like the ability
    • 1:39:51to asynchronously request information from an external server or the ability
    • 1:39:55to do computations based on the values of the state, like we saw within React,
    • 1:39:59we have the ability to create very interesting,
    • 1:40:01engaging, dynamic user interfaces very, very quickly, all just
    • 1:40:05using the power of combining Python and JavaScript.
    • 1:40:09That was Web Programming with Python and JavaScript for today.
    • 1:40:11We'll see you next time.
  • CS50.ai
Shortcuts
Before using a shortcut, click at least once on the video itself (to give it "focus") after closing this window.
Play/Pause spacebar or k
Rewind 10 seconds left arrow or j
Fast forward 10 seconds right arrow or l
Previous frame (while paused) ,
Next frame (while paused) .
Decrease playback rate <
Increase playback rate >
Toggle captions on/off c
Toggle mute m
Toggle full screen f or double-click video