[MUSIC PLAYING]
SPEAKER 1: OK, let's get started.
Welcome back, everyone, to CS50 Beyond.
So for a little bit of context from where we've been so far--
thus far in CS50 Beyond, we've mostly been building on a lot of the topics
that we saw in CS50.
We saw each HTML.
We saw CSS.
We saw JavaScript.
We saw a SQL.
And we've been taking those ideas so far this week and just building onto them,
showing you some additional features, some more advanced capabilities,
building some more sophisticated applications.
Today we're really going to introduce something entirely new--
that being React, which is a JavaScript library built by Facebook, which
is designed to make it very easy to build interactive and dynamic user
interfaces.
And React is going to be a totally different way of thinking about
how to build web applications, and how to build user interfaces.
And we'll go through a bunch of examples to give you
a sense for how this works, how to think in React,
and ultimately, how to program in React.
And so, React has a couple of key concepts-- a couple of key ideas
you want to be thinking about.
And the first of those ideas is that React
is a declarative way of programming.
And so, thus far in most of what we've done in CS50 and in programming more
generally, we've been doing what you might call imperative programming.
In imperative programming, we write code that
tells the web application what to do.
We want to insert this thing into the web page.
We want to manipulate the web page in this particular way.
But whereas imperative programming is a model where we say,
this is what we want the web application to do,
declarative programming is a style of programming where we say,
this is what we want the web application to look like.
This is how the application should look.
And we're going to let React take care of figuring out
what the application should do in order to make the application
look like the way that we want to look.
And you'll see in a moment what that actually means,
and what it actually looks like.
So that's the idea of declarative programming.
And in order to achieve that goal, there are a number
of tools that React is going to use.
The first of which is that, instead of using JavaScript,
it's going to use a slight extension to JavaScript--
a variant on JavaScript that has a few more features-- called JSX,
or JavaScript X. And the idea of JSX is, whereas in JavaScript we have a whole
bunch of different types of values-- we have integers, and we have strings,
we even have functions and arrays and so forth--
in JSX, we can treat each HTML elements as values of their own.
So in JSX, you might see code that looks something like this--
const, some variable name, equals, and then an h1 block, for instance.
Like HTML code that can be a value in JavaScript
that we can assign to a variable, that we can loop over at some point,
potentially, that we can do calculations and computations on.
This sort of code is common in JSX and has some special meaning.
So that's something that we'll see in React in just a moment.
And so in order to make this work, there are a couple
of libraries that we're going to need.
I'll just briefly describe what they are,
and then we'll actually start using them.
React is going to be the library that's going to actually allow us to do
the building of these user interfaces.
There's a separate but related library called ReactDOM that's going to take
care of taking the React components that we create--
more on components in just a moment--
and actually inserting them into the web page, into the DOM--
the document object model.
And then finally, we're going to be using a package called Babel.
And we're using this because most web browsers,
in fact, all of our modern web browsers don't understand JSX code natively.
So code that looks like this, Chrome and Safari
don't normally know how to understand this code and figure out what it means.
So what we need to do is translate this sort of code
into regular JavaScript code that our browsers can understand.
And Babel is going to take care of doing that translation for us, such
that the browsers can actually understand the code that we're using.
So in a moment, in our HTML pages, in the head section
where we might include JavaScript, we're going
to be including a whole bunch of scripts-- one for React,
one for ReactDOM, one for Babel.
You can just copy these scripts and put them at the top of your HTML page.
And you'll see in a moment how that will eventually become useful.
So all of React is really designed around this idea of components.
When we're going to think about our web application, we're going to try
and divide the application into the components
that make it up, and then start to analyze,
how is that component going to behave?
And a component is going to end up looking a little something like this.
If we wanted a component that was just going to say "Hello",
we're going to define a class called "Hello" in JavaScript,
and extends React.Component is basically just saying
that this Hello class is a React component.
And what do we do from there?
Well, each React component needs to have some notion of,
what does it look like when I render this component to the screen?
When I try and take this component and display it
on my web page, what should show up?
Declaratively, what is going to show up on the page?
And so, every component is going to need a render function.
And that render function is just going to describe what
it is that this component looks like.
And in this case, this Hello component, very simply inside
of its render function, is just going to return a JSX element
from HTML like code, that it's just a heading that, in this case,
says "Hello".
So we've defined a react component.
This is our first React component.
And all it does is display an h1 tag.
So I'll show you that right now.
We'll actually build our very first React application.
So I go into a code editor, create a new file.
I'll call it "hello.html".
All the source code examples for today are already
online if you want to take a look at them.
So let's say, DOCTYPE HTML.
In the header section of the website, I'm
going to need to include those JavaScript libraries.
I need to include React and ReactDOM and Babel.
And so I'll go ahead and go back to these libraries.
I can just copy these scripts and paste them into the page.
I'll give this a title as well.
We'll just call it "Hello".
And now in the body of the application, I
need to create a space inside the body of the application
where my React application is going to live.
And so I'm just going to create a div--
some vertical section of my page where I'm going to insert my application--
whose id is going to be app.
And it's just going to be an empty div.
Nothing inside of it.
This is where my application is going to go.
And now, let me add some JavaScript code--
some JSX code that's going to render a React component inside of my web page.
So I'm going to use a script tag, but I'm
going to use a special type attribute.
The type is going to be text/Babel.
What this is basically going to say is that this is not regular JavaScript.
This is JSX, that special version of JavaScript
that I mentioned a moment ago.
And the fact that I'm labeling it with "type text/Babel"
is going to tell Babel the package that, OK, this is JavaScript code that I'm
going to need to translate into regular JavaScript
before the browser is going to be able to understand it.
So when we open the page, Babel is going to first take
the step of translating it for us, so that Chrome or Safari
or whatever browser you're using can actually understand this code.
So now, let me go ahead and define my first React component.
So we're going to call it class Hello extends React.Component.
So I've created a React component.
And remember, the one thing that every component needs
is a function called render that's going to say, what should this component look
like when I render it to the screen?
So I'll define a function called render.
And what this function render is going to do
is it's going to return something.
And it's going to return, let's say, in h1 tags, the word "Hello".
This return statement-- I've enclosed the whole thing in parentheses
just in case I need the HTML to span multiple lines.
It's not really necessary in this case, but you'll
see this pretty commonly as you begin to build larger and larger components.
So all the Hello class is doing right now
is defining a component that describes what it should
look like when it's on the screen.
Questions so far?
All right, the next step, and really the last step
of building this particular application, is just saying,
I actually want to render this component on the screen.
And so, in order to do that, we're going to use ReactDOM,
which is that library that lets us take React components
and put them into the DOM into our page.
And we're going to say ReactDOM.render.
And ReactDOM.render takes two arguments.
The first argument is, what is the component that we want to render?
And the component we want to render is Hello.
And now you can treat Hello just like you would treat any other HTML
element for example.
I'm just going to say, Hello as though it were an HTML tag like div,
or h1, or some other tag.
Because I have defined it as a component.
And so now I can just say, I want to render the Hello component in my page.
And where on the page do I want to render it?
Well, I want to render it here.
In other words, the section of the body that has id app.
And as we've been doing previously in the week,
if I want to get at that particular part of the page, I can just say,
document.querySelector("#app") to say, get the thing that has id app
and insert this Hello component into the page there.
So I'll show you what it looks like, assuming this
all works, and then we'll go back to the code.
I'll open up hello.html.
And all right.
It just says, "Hello".
It displays that as an h1 tag.
And the way it did that is because I took this hello component
and rendered it into the DOM.
So in 28 lines of code, we've defined our first React application.
What questions you have?
All right, so let's move on a little bit and look at some more things
that we can do here.
So we have this class called hello, this can React component.
And once I have a React component, I can reuse that component.
I can use it multiple times if I want it to do different things.
And so, let me to find a new React component.
I'll call it "app" that's going to extend React component.
And the render function of this app is just
going to say when you render this application,
go ahead and render a div, inside of which are two hello components.
You can nest components within each other, so to speak.
So inside of my app now, I'm saying, let's render
two hello components, one after the other.
And inside the DOM, let's go ahead and just render the app component.
So I'm rendering the app component.
And what does the app component do?
It renders two hello components.
And each hello component is just going to say "Hello".
I refresh the page.
And OK, now I have two hello components that are displayed on the page.
Questions about anything so far?
I'll go back to the code so you can take look at it.
All right, so this is the basics of what React
is about-- defining these components, and then defining
what the page should look like, and then letting that render.
Though so far, all we've done is render something
that we could have done much more easily with just HTML and no JavaScript.
So let's take a look now at what we want to happen
if we want different components to behave differently.
Maybe I don't just want hello to say just the word "Hello".
Maybe I want it to say hello to a particular person, for example.
And so maybe I would like to add some attributes,
or what we're going to call props or properties to these components.
And so I want to say hello to a particular person.
I'll pass an argument, or a prop, to this hello component-- name being Josh,
for example--
and another prop whereas the name is Athena.
And maybe I want more hello components-- one where the name is Julia,
and one where the name is Krishna, and we'll do one more for Andrew.
So now I've got five different hello components,
each of which I'm providing some different information.
I'm providing in a name, a prop, into the hello component.
And now inside the hello component, I'm going to use that information.
Rather than just say "Hello", I'm going to say hello to whatever the name is.
And so, in JSX, this type of syntax-- if I want to plug in some value here,
I'm just going to use curly braces.
And in order to get at this component's props and get at the name property
of those props, I'm going to say this,props.name.
So the hello component says "Hello", and then in curly braces,
let's plug in this.props.name to get the name property of this component,
and plug it in there.
And then my application is just going to render
a whole bunch of hello components, each of which
is provided with a different name prop.
So I go ahead and refresh the page.
And all right, great.
I see five different components, each of which
now behaves differently based upon what properties it was initially
provided with.
Questions about anything so far?
Yeah?
AUDIENCE: Could you use Jinja [INAUDIBLE] difference between
[INAUDIBLE]?
SPEAKER 1: Could you use Jinja?
So Jinja is a templating language.
You couldn't use Jinja in just this HTML page,
because you'd need some sort of renderer that actually processes Jinja.
But you could imagine combining Flask and React together.
And there are certainly ways to do that if you wanted to.
Other things?
Yeah?
AUDIENCE: Was name an arbitrary value?
SPEAKER 1: Yes, name was just an arbitrary choice.
You can create props of any name that you want.
You can call them whatever you want, so long as you're consistent.
The only thing that matters is that this name of the prop
here matches up with this name here, so that I
can reference the correct property.
Yeah?
AUDIENCE: I'm just a little confused in the relationship between [INAUDIBLE]
SPEAKER 1: Yeah.
So the way to think--
AUDIENCE: I'm a little confused about [INAUDIBLE]..
SPEAKER 1: Good question.
So the way to think about it is, the hello component--
what I have here between lines 13 and 22--
is a component that says "Hello".
And it's saying hello to a particular person.
And the way that it's doing that is, it's going to draw on its properties.
When I define the hello component here, I don't yet
know what those properties are.
So I'm just saying, whatever those properties are, plug in the name
here, even if I don't know the name yet.
I don't actually use the hello component until inside of my app,
where inside of the app, I'm saying, put a hello component here.
And in particular, put a hello component here
who has a name property equal to Josh, for example.
That's the way that that's working.
Yeah?
AUDIENCE: In the very beginning of the first example
you used the line at the bottom [INAUDIBLE]..
Why do you not need the same format inside the [INAUDIBLE]??
SPEAKER 1: So why do I not need a second ReactDOM.render
inside of the app class?
I only need the ReactDOM.render function in order
to insert a component into the DOM.
So I want to insert into the DOM, at this section of the page, the div that
has an id of app, I want to insert the app component.
But the app component itself contains the hello components already.
So I don't need to tell the hello components where to go.
When I render the app component, that will implicitly
render all of the components that are within it.
Yeah?
AUDIENCE: You said the alt values for [INAUDIBLE]
didn't provide a name [INAUDIBLE].
SPEAKER 1: If you didn't provide a name.
Sure, certainly.
So if I wanted to have some sort of default--
if I have this.props.name and there is no property called name,
then the value of this.props.name is going to be a special value,
like undefined in JavaScript.
And so, a common way in JavaScript to get at some sort of default is
by saying, this.props.name or--
two vertical bars meaning or--
and then in quotation marks, I can have whatever I want the default name to be.
And so, maybe the default name is going to be Andrew.
And now, even if I don't include name on this last one,
just say hello, assuming all goes right--
OK, it still says "Hello Andrew" on the last iteration of the page.
And the reason that works is, when I say this.props.name or Andrew,
if this.props.name has a value, then this expression will short circuit,
so to speak.
It will just use this.props.name because it already is a value.
But if this.props.name is undefined, then
it's going to go to the thing on the other side of the or expression
and say, OK, let's go see the other thing.
And that, in that case, is Andrew--
in this case.
Question?
AUDIENCE: Can you have a bunch of or expressions?
SPEAKER 1: Can you have a bunch of or expressions?
Yes.
There shouldn't be any reason why not.
Other things?
OK.
So how do we feel about this much so far?
Do we need more examples of this stuff?
Or do we want to move on?
AUDIENCE: Can we have another example?
SPEAKER 1: Sure.
So let's see another example.
In this case, let's try an example that's also going to say hello.
Then we'll add an additional feature to it in just a moment.
So we're going to have a hello component that is just
going to say "Hello", for example.
And let's go ahead and just return the hello component.
So all app is going to do-- this component-- is
return a hello component.
And all that hello component is going to do
is return an h1 that says "Hello", for example.
So OK.
This is just going to say "Hello", and that's all it's going to say.
Let me now add to this hello component.
Instead of just returning an h1, let me wrap this whole thing inside of a div.
Let me also add a button that says "Click Here".
So all right.
I have "Hello" and I have a button that says "Click Here".
And I got that by just saying, inside the hello component,
you should have an h1 one that says "Hello",
and you should also have a button that says "Click Here."
Now once we have this button, we can begin to add functionality and features
to this component.
So I could say, button onClick equals something.
I can type in the name of a function here
for what function should run when this button is clicked on.
And so I could say, this.--
and I'll just call it "handleClick".
It's a pretty conventional name for what should
happen when the button is clicked on.
Again, using curly braces to mean plug in some JavaScript here.
And now I can say, OK, handleClick is going to be a function,
using the arrow syntax for the function.
And this function right now is just going to alert and say hi.
So let's try this.
We'll just refresh this page.
We have a "Hello" in h1, and a button that says "Click Here".
When I click here, I get an alert.
And that alert says "Hi!"
Again, how did that work?
Inside of the hello component, we have an h1 tag that just says "Hello",
and then a button.
And when we click on that button, we're going to run this.handleClick.
In other words, the handleClick function or method of this class--
this class called hello--
here is that handleClick function.
And all it's going to do is display an alert that says "Hi!"
Questions about any of that so far?
All right, we'll slowly build up into more sophisticated things.
Question, yeah?
AUDIENCE: So the same way the name wasn't defined below here
but name is [INAUDIBLE] can we do the same thing with [INAUDIBLE]
define that function differently whenever we call hello with an app.
SPEAKER 1: Yes.
You can, in addition to just providing--
so before, we said, hello, name equals Krishna, for example.
And we provided a string in as the value of the property name.
You could, if you wanted to, provide in a function,
like this.someFunction, and provide some function into the components,
so that different components use different functions to behave
in different ways.
That's something you can do as well.
We may see an example of that later.
Yeah?
AUDIENCE: Can you explain the line at the bottom of the [INAUDIBLE]??
SPEAKER 1: The line at the-- this line?
Yep.
So this line is just taking this component that we've written
and actually inserting it into the application.
So as of this point, all I've done is define,
this is what an app should look like and how it should behave.
But I haven't actually taken that app and put it into my web page.
It's not until line 40 here that I actually say, take this app component
and actually insert it into whatever the thing that has id app is,
and actually putting that into the web application.
AUDIENCE: And you're not using the [INAUDIBLE]??
SPEAKER 1: Yes.
In this case, app has a hello component inside of it.
You could imagine that we probably don't need it, because this app component is
just rendering the hello component.
So I could replace this with just hello.
But it doesn't matter in this case.
They're sort of interchangeable.
Yeah?
AUDIENCE: [INAUDIBLE] so why is there [INAUDIBLE]??
SPEAKER 1: This is referring to this component.
In other words, this hello component.
And the hello component currently has two functions inside of it--
a render function or method, and then handleClick.
And so we're saying, run the handleClick method when the button is clicked on.
Yeah?
AUDIENCE: So how would you pass an argument [INAUDIBLE]??
SPEAKER 1: How would you pass an--
AUDIENCE: If you wanted to alert [INAUDIBLE]??
SPEAKER 1: Oh.
You can access this.props.whatever from inside of your functions as well.
So if we still had a name property, you could say, hi,
and then you could add on this.props.name, for example.
You could access the properties from inside of the functions.
Yeah?
AUDIENCE: So in the beginning of the code
you wrote you had hello [INAUDIBLE] and then in [INAUDIBLE]..
SPEAKER 1: Yep.
AUDIENCE: But how do you know what this is referring
to because there is no [INAUDIBLE].
SPEAKER 1: So this is just referring to the hello component.
And React is automatically going to fill in props
with any of the properties that are passed into the hello component.
So as long as you provide attributes in this style of,
name of the component, and then name equals something,
name is automatically going to become one of the props.
And its value, in this case, is going to be Julia.
Other things before we go on?
Yeah?
AUDIENCE: In a problem [INAUDIBLE].
SPEAKER 1: Yeah.
It could be any JavaScript value.
Yeah.
Yeah?
AUDIENCE: Does the handle click function have to be defined like that
or could we define in the normal function [INAUDIBLE]??
SPEAKER 1: You could define it differently.
Although, the arrow function syntax is going to--
it adds a couple little nuances.
It's going to make sure that it handles the this binding correctly.
Long story short, JavaScript is a little bit funky about the way
it handles the keyword "this" and what the keyword "this" means.
And so to be safe, most of the time for event handlers,
you'll want to define it this way.
No need to worry too much about that though.
Yeah?
AUDIENCE: [INAUDIBLE] script code separately [INAUDIBLE]..
SPEAKER 1: Yes.
In fact, in most production environments, what you'll really do
is separate each component into a different file--
into a different JavaScript file, and then you'll
just combine them all together.
AUDIENCE: So it's only considered JavaScript and not like [INAUDIBLE]??
It wouldn't be a different extension?
SPEAKER 1: Yeah.
So in actuality, what most people will do--
and we'll probably take a look at this tomorrow-- is that,
rather than have the page translate all of the JSX into JavaScript
every single time, usually what people will do
is they'll write the JavaScript JSX code once.
And then before they actually push their code to the internet,
they'll compile the code into regular JavaScript,
and then deploy that, such that it is playing JavaScript
that any browser can understand.
And that just works for efficiency reasons,
so that you don't need to keep recompiling the code every single time.
Because the recompiled code is going to be the same.
But we'll take a look at that tomorrow.
All right.
So far, all we've done is come up with a lot of JavaScript syntax
to do what would have been pretty easy to do with just HTML.
So let's now actually take a look at why it
is that React is going to give us additional--
is going to make it easier to actually write certain types of applications,
as opposed to just more wordy, which seems to have been so far.
And the main reason that it's going to be helpful
is when it comes to thinking about state,
and the state of our application.
So far, when we've been building applications,
we've been writing things imperatively.
When you were writing your quiz application, for instance,
you changed the variable referring to what question
number you're currently on in the quiz.
And then you had to actually say, all right, let's update the page now.
Let's update the DOM to actually use this new question.
Or when you changed the score for the game, for instance,
you actually had to say, all right, let's now update the page
to take this variable relating to the score
and put it into the web application.
What we're going to do with React with declarative programming is say,
on this page, we're going to have this part of the page
just draw information from whatever our data is.
So all we have to do in order to update the page is just
change the data-- change the state of the application.
And the view of the application-- what the application looks like--
is going to change to reflect that.
And so, let's do a simple example of that.
We're going to define a class that's going to count, much like we
did in a JavaScript example before, whereby
we would have a counter that is going to just count when you click a button that
says increment, increment, increment.
What we're going to do is, we're going to define some application state.
And the initial state we need to define when we first create the component.
And in Python, we did this via a function called underscore, underscore
init--
the constructor function for what happens when you first
create a new Python object.
JavaScript has something very similar.
It also has a constructor function.
It's actually called constructor.
And the constructor takes as its arguments props--
all of the properties that the component is going to have.
And there is one line here that has to do with object oriented programming.
Because the counter class-- this component--
is extending the regular React component,
we need to add this special line called super(props).
Again, don't worry too much about this.
But the long story short of this line is, we're basically saying,
React's code for how a component works needs to use those props.
And so we'll go ahead and provide it to what's
called the super class, which is React.component.
Again, no need to worry too much about that line.
It just needs to be at the top of your constructor every single time.
The interesting part of the constructor is
that the constructor is where we're going to define
the state of the application--
what it is that this component needs to keep track of.
So this.state we're going to set equal to some JavaScript object--
some collection of key value pairs that's
going to represent the state of the object,
or the state of this particular component.
And so, the counter--
all it needs to do is keep track of some variable that's
going to keep track of what the current count value is.
So we can start by having this.state have a key called
count and a value of 0.
Basically, just saying that this component
is going to start off by displaying a 0, for example.
So I'll show you that in practice so that it hopefully
becomes a little bit clearer.
I'll go ahead and create a new file.
We'll call it counter.html.
And I'll go ahead and take all this code, and put it back in here at least
for now.
And instead of rendering a hello component,
I'm going to render a counter component.
And all right.
What is the counter component going to do?
Well, inside of the constructor--
again, super(props), just to make sure the constructor works OK--
we're going to define the state of the application.
And the state of the application is going to have a count of 0
to start with.
This is the starting value of this particular piece
of the state of my counter.
And now, what is my render function going to do?
Well the render function is going to return a div inside of which
is going to just be this.state.count.
So in order to access the state of my component,
I can say something like, this.state.count,
and that's going to insert the current state's count value into my application
at this point.
If I open up counter.html--
all right, great.
I see the number 0 because that's the current value
of the state in JavaScript.
Questions about that so far?
Yeah?
AUDIENCE: Is props like--
[INAUDIBLE] or is it specifically [INAUDIBLE]??
SPEAKER 1: Props is specific to-- it's a special name in React syntax.
AUDIENCE: Like [INAUDIBLE].
SPEAKER 1: Yeah, this is specific to JavaScript, props is specific to React.
But they both are special names.
AUDIENCE: So then are props in general more like keyword arguments in Python
as opposed to standard arguments because it
would be like name equals something as opposed to just putting in quotes
whatever the name you want.
SPEAKER 1: Yeah, you can think of them as keyword arguments.
That's a good comparison.
Other things?
Yeah?
AUDIENCE: This is just like a kind of general syntax question.
When should you use the semicolon?
SPEAKER 1: The semicolons are actually usually optional in JavaScript.
So most of the time, it's not going to matter whether you
include the semicolons or not.
I'll generally defer to using the semicolons most of the time.
Though I will occasionally forget one.
Other things?
OK, so notice now that I can change the value of the count variable
in the state object.
And that's going to change the page.
If I change count to 1, for example, and refresh the page,
the page changes in response to that state.
But of course, what I'd really like to do
is to add some code such that this component will modify its own state.
So let me go ahead and take this.state.count,
put that inside of an h1 tag, and add a button called "Increment".
And when I click the button--
onClick-- let's go ahead and run the this.increment function, which
is a function that I'm going to write.
Here's my increment function.
And what I would like to do-- what you think might be the easy thing to do is
just to say, this.state.count--
if I want to increment it, let's just for simplicity's sake,
say change it to 1--
you might think I would say something like this-- this.state.count equals 1.
And that would be nice to say.
But unfortunately, React is a little bit more complicated than that.
React does not let you modify the state directly.
And the reason for that is, React is going to be smart about things.
It doesn't want to reload parts of the page
if it doesn't need to, for efficiency reasons.
And so, if you want to modify the state of the application,
you need to use a special function called this.setState.
This.setState is a function that's going to take a JavaScript object,
and it's going to let me change the state of the application.
So if I want to change it to have a count of 1, for example,
this would be the code that I would use.
If I want to change the state to have a count of 1,
I call this.setState, passing in a JavaScript object,
setting count equal to 1.
I'll show you what that looks like, and then we go back to the code.
Refresh the page, it's a 0.
And I have a button called "Increment".
And if I click the Increment button, OK, the 0 changed to 1.
I didn't have to say, go into the h1 tag and get rid of the 0
and replace it with a 1.
All I did was, initially, I said, inside of the h1 tag, let's go ahead
and have whatever the value of this.state.count is.
And if I ever change the state, as via calling this.setState,
that's going to change the value of this.state.count.
And that's going to result in a different value being
inserted into the h1 tag there.
Question?
AUDIENCE: If your initial state is [INAUDIBLE]
how does it update or would you have reset the state for all
of the other variables?
SPEAKER 1: Oh, good question.
So the question is, what if my state were more complicated?
In addition to having count, I also have some other attribute
1 that's equal to "hi", and some other attribute 2 the equal to "bye".
What happens to attribute 1 and attribute 2?
If I call setState, count goes to 1.
Any key that's not included in the set.State object
is just going to remain unchanged.
So all setState is doing here is, it's going to set count equal to 1.
But anything else in the state, if I didn't mention it explicitly,
is just going to stay as is.
So you don't need to worry about resetting those same values
to the same things again.
You just need to say, what is it about the state that I want to change?
And put that into setState.
Yes?
AUDIENCE: In setState could you add a new key to your state [INAUDIBLE]??
SPEAKER 1: In setState, could you add a new key to your state?
You probably could, but probably not a good idea to.
Any state you want, you probably want to give it an initial value
inside of the setState.
Yes?
AUDIENCE: Is React an abstraction of that [INAUDIBLE]??
You mentioned we're not writing the JavaScript to go in [INAUDIBLE]..
So is React actually doing that somewhere else or is it [INAUDIBLE]??
SPEAKER 1: Yes.
So React is taking care of the process of actually
updating the DOM whenever it needs to.
But it's handling that logic.
And so, all we need to worry about is what the page should look like.
And React does the heavy lifting of figuring out what to insert
and what to remove from the DOM.
And the advantage here is that it makes sure
that our data and our user interface stay in sync--
that it's possible in the quiz application,
if there were a bug in your quiz application,
that you could have your variables not be consistent with what it is the user
is seeing on the screen.
React is going to make sure that those things always line Up
so it eliminates a large class of potential bugs
that you could have in your application.
Yeah?
AUDIENCE: Why do we have [INAUDIBLE] state instead or props?
SPEAKER 1: OK, what's the difference between the state and props?
Props you can think of as attributes that you're
going to provide into your component.
And the component never changes its own props.
They're sort of information you provide to the component about how
that component should behave.
And the component will never change its own props.
State is something that a component has that the component might
change at some point in the future.
So something like the name that we're saying hello to, assuming we never
want the hello component to change who is saying hello to,
that should be a prop.
But if it's something like the counter, where the counter component is
going to change the value of the count, that
should be part of the application state.
Yeah?
AUDIENCE: Can the initial value of the state
be dependant on props passing [INAUDIBLE]??
SPEAKER 1: Yes, you could make the initial state dependent upon the props.
You can do that.
All right, so this application doesn't quite work just yet.
Because right now it says 1, and I click Increment, and it stays at 1.
Because all I'm doing right now on the Increment is setting count equal to 1.
So of course, the simple way to actually do the increment
would be to set count equal to what?
AUDIENCE: Count plus 1.
SPEAKER 1: Count plus 1.
And count is located inside of this.state.
So I could say, this.state.count plus 1, would be one way to do that.
So I set the count equal to whatever the current count is plus 1.
I refresh the page.
OK, now it's 0.
I click Increment.
It increments to 1.
I click again, and every time, the state of the application is changing
and the number is going to increment as a result.
And so you can do that as much as you want
to do by calling this.setState, updating the state to be
whatever you want the new value to be.
Questions?
So, a small, little nuance--
for if you actually go on to really want to start
building React applications that are larger in scale--
in general, this is considered poor design
to set the state and reference this.state
inside of the setState function.
Reason being, if you have multiple things happening simultaneously,
it's possible that two this.setState calls
might be happening at a similar time.
And you might end up with a race condition--
something similar to what we described yesterday with SQL--
where someone else might modify the value of this.state.count before we
have an opportunity to actually run this function.
And so, in practice, React recommends that,
if ever your new state is going to depend on your previous state,
then you should actually change this.setState.
So this.setState has a couple of possibilities.
It can take just a JavaScript object, describing
what the new state should be.
But it can also take as its argument a function
from the old state to the new state.
So I could say, this.setState is going to be a function that takes--
I'll call it "oldState" to be explicit--
a function from old state to--
and then, in parentheses--
the new state, where count is going to be oldState.count plus 1.
Usually, this is just called state and not oldState,
but I'm calling it oldState for clarity.
This is going to do basically the same thing that our previous code did.
But it's a little bit more secure.
By providing a function that says, here's
how you translate the old state to the new state--
just take the old state count and add 1 to it--
that avoids against the possibility of race conditions.
So you'll see me do this from time to time through the examples.
And just know that I'm doing that for security purposes, just
to prevent against potential bugs.
But that's a small nuance of the way it works.
Yeah?
AUDIENCE: Why is it necessary to--
or what is the differentiation between referring to count as count
and then having refer to it as the oldState or [INAUDIBLE]??
SPEAKER 1: So this count on the left hand side
is just the key of a JavaScript object.
So it's-- much in the same way that when I was defining state up here,
count was just the name of the key of the object that I'm assigning
to a particular value.
Whereas, if I want to actually reference the current value of count,
there is no variable just called "count".
It's stored inside of this.state.
So to be able to access count, I need to use this.state.count.
But if I just have some JavaScript object,
I can have a key in that object that is called "count".
That's the difference there.
Yeah?
AUDIENCE: Why is oldState [INAUDIBLE]?
SPEAKER 1: This is just a function.
And setState, React's logic is going to take care of automatically saying,
if I provide a function to setState, it's
going to pass the current state into that function.
And then we're just going to calculate the new state based on that.
AUDIENCE: Right, but why doesn't oldState not count [INAUDIBLE]??
SPEAKER 1: React handles this part of it for us by taking this function
and providing the current state to it as the argument to that function.
So that when it's calculating what it should set the new state to,
it's going to say, all right, given this current state,
let me pass it to this function.
And whatever comes back should be the updates
that I need to make to the new state.
I'll leave it up here if you want to keep looking at it.
Yeah, another question?
AUDIENCE: So oldState is also [INAUDIBLE]??
SPEAKER 1: Yeah.
In fact, normally it's just called "state".
But for clarity, I called it "oldState" so
that it would be a little bit clearer.
Yeah?
AUDIENCE: If you had a more complex JavaScript object,
how would you index into it given the dot index?
Like instead of [INAUDIBLE] you have different elements within elements.
SPEAKER 1: You could just chain dots together.
If you have some key that is equal to some object,
and there's some key inside that, you can continue to chain that.
Yeah?
AUDIENCE: Why does passing the function of setState,
why does that prevent race conditions?
SPEAKER 1: So the reason this is going to prevent
race conditions is because React will make sure
that, when it's calling setState, it's going to provide it
with the current value of the state.
And that's going to give it a new state.
And if there's some other setState function happening elsewhere,
potentially concurrently, it will make sure
that they don't interfere with each other.
As opposed to, if we were just referencing this.state.count,
if that line was taking a long time, there
could potentially be interferences there that are happening.
Yeah?
AUDIENCE: [INAUDIBLE]
SPEAKER 1: Right.
This is something else on the same page that could be happening concurrently.
This is a simple example.
So it's not really ever going to happen.
But you can imagine more complex examples where that could be a problem.
OK, just for sake of example, let's go ahead and try and extend this
to add a Decrement button to decrease the value of the count.
So a button that says Decrement--
when I click it, onClick, we'll do this.decrement.
And what Decrement is going to be is a function that
sets the state of the application, taking the old state and saying,
OK, the new count should be whatever state.count was minus 1.
All right, I now have an Increment button
that increases the value of the count, and a Decrement button
that decreases the value of the count--
each working just by changing the contents of this.state
by calling this.setState function.
Yes?
AUDIENCE: Can we instantiate a multiple of these?
SPEAKER 1: Sure.
Can we instantiate a multiple of these?
If I add another counter here--
and why not?
I'll add a third counter--
we can reuse components as much as we want.
And each component has its own state inside of it.
So this component's count state is going to be
entirely independent of this component's count state.
And it's going to be entirely independent of this one.
Questions?
Yeah?
AUDIENCE: Can you-- if you wanted to pull in [INAUDIBLE]
how do you access it if you're automatically generating because they
don't have their own IDs [INAUDIBLE].
If I wanted to use in another function the value
of the [INAUDIBLE] JavaScript.
SPEAKER 1: Yeah, if you wanted to use this value,
you would then just be able to access the state of that component,
assuming you're inside of that component.
And you can reference that state to be able to do something with it.
And we'll see an example of that in just a moment when we try
and build something a little bit larger.
All right, let's go ahead and try a bit of a larger example.
Are there any other questions about the basic ideas of what's
going on here so far?
Hopefully it'll become clearer as we begin working with it too.
All right, what we're going to do now is build a game.
And this is going to be a game that I used to use with my younger brother
when he was growing up starting to learn addition,
where we would just show him addition questions like, 3 plus 5.
And you'd have to type in an answer.
And if you get the answer right, you get some points for it.
We'll implement a graphical web-based version of that sort of game.
And so I'll go ahead and create a new file, and call it addition.html.
We'll start with the same contents as hello, for now.
And all right, what is our application going to do?
We don't need a hello component anymore.
We'll change the title of hello to addition, for example.
And let's go ahead and create this application.
We'll add a constructor.
And so, let me show you for a moment what the final game should look like.
And then we can think about, OK, what state
do we need to keep track of in order to make this work?
And so let me go into--
All right, this is what this game ultimately is going to look like.
It's going to show us an addition problem.
You type in the answer.
You get it right, the score increases.
You get it wrong, and the score stays the same.
So I get it right, and I keep adding to my score.
And I get it wrong, and the score doesn't change.
All right.
So given that-- that's the way we want the application to behave--
what needs to be in the state of this application?
What are the things I need to keep track of here?
What changes about this application is one way to think about this.
There are multiple things.
Yeah?
AUDIENCE: [INAUDIBLE]
SPEAKER 1: The question that's being shown.
Sure.
And the question that's being shown has two parts.
It has num1, which is just going to be some number.
We'll maybe start it with 1.
And it has num2, a second number that's also-- we'll start it off
as 1, though these are going to change.
So great.
The numbers that are shown on the screen--
this plus that-- those are parts of the state,
because we might want to change that part of the state.
What else is part of the state of this application?
Yeah?
AUDIENCE: The score?
SPEAKER 1: The current score.
Great.
The score is part of the state.
And that's just going to be 0 for now.
Anything else you can think of?
Yeah?
AUDIENCE: The answer.
SPEAKER 1: Yeah, the answer.
The thing that I'm currently typing in the input field-- in the response
field.
That's also going to be part of the state as well.
So I'll go ahead and add response, and just
set that equal to the empty string.
Because initially, I haven't typed in anything at all.
So great.
Here are some basic components that are going to make up
the state of this application.
And let's go ahead and render this application.
We're going to render a div.
And maybe in an h1, just for now, we'll go ahead and have the addition problem
here.
this.state.num1 plus this.state.num2.
That's going to be the question that I'm ultimately going to ask.
It's just this plus that.
If I open up addition.html--
all right, great.
I see an addition problem where I'm drawing the numbers from the state.
later if I change the state and change those numbers,
this page will change automatically.
And now in addition to that, I'm also going to need an input field--
an input field whose value is going to be this.state.response,
in other words, whatever the user has currently typed in.
Questions about that?
All right, so now I have a place where I can ask a question,
and a place where I can type an answer.
And now, if I actually try and type an answer, something sort of strange
happens.
But it will make sense if you think about what's actually happening
in my code and what I've written.
If I try and press 2, for example, to answer 2--
I press 2, but OK, nothing showed up in the text field.
I can keep pressing whatever keys I want to on the keyboard,
and nothing's showing up in the text field.
It's highlighted, my cursor is there.
So why is nothing changing in the text field?
Any thoughts?
Yeah?
AUDIENCE: [INAUDIBLE]
SPEAKER 1: Yeah, exactly.
Response inside of my state is set to the empty string.
And this input field right now, I'm saying its value
is this.state.response.
And this.state.response is never changing.
And so what's in the input field is always going to be empty.
It's never going to have anything else there.
So what I need to do is actually add some code to say,
what should happen when I actually change the value of the input field?
So the input field has a property called "onChange".
And I'm going to say, when you change the input field, let's call a function.
And I'm just going to call it "updateResponse".
So this.updateResponse is going to be a function that's
going to handle when I type something into the input field.
OK, so here is updateResponse.
It's going to be a function.
That function-- all functions that are event handlers
can take as argument their event.
And we're going to need this in just a moment, and you''ll see why.
Because what I want to do is, I want to update the state--
this.setState-- and I want to set the response to event.target.value.
And event.target.value is nothing specific to React.
It's just JavaScript for saying, here's the event--
the event of changing the input field.
The event's target is what triggered the event-- the input field, in particular.
And what is the current value of the input field, meaning,
what it is that I've typed into the input field.
I'm going to update the response to be that.
So what have I done here?
I've said on this input field, whenever it changes,
call the updateResponse function.
And the updateResponse function is going to set the state of my application,
updating the current value of a response.
And so, if I press Refresh now, now I can actually type numbers in here.
I can add 2, 3, whatever number I want.
If I scroll back here, you can actually see what I'm doing here.
If I say, current guess is, and then let me fill in this.state.response--
just plug in whatever this.state.response is right now.
If I refresh the page, and I start typing 2--
current guess is 2.
8, current guess is 28.
2, current guess is 2.
Empty, the [INAUDIBLE] goes empty.
The page is changing in response to the state
without me needing to go in and actually modify things,
because I have pulling from this.state inside of the render function.
Yeah?
AUDIENCE: Does the order of the functions matter in the same way?
Is it fine to have updateResponse after Render or is it fine to
have it before as well?
SPEAKER 1: The order of the functions doesn't really
matter-- updateResponse could be higher up, if I wanted it to be.
AUDIENCE: [INAUDIBLE]
SPEAKER 1: Yeah, when you define the class,
it's going to go through all the methods.
So it knows what methods it has.
And so it doesn't really matter what order they're in.
Yep?
AUDIENCE: How does the updateResponse know that event is [INAUDIBLE]??
SPEAKER 1: I specify it here, that the input's onChange attribute
is this.updateResponse.
So when the input field changes, it's going
to call the updateResponse function.
And the event that did that calling is the input field's change event.
And so it has access to the input field and can access
the current value of the input field.
Other things so far?
All right, let me also, instead of showing the current score,
let me go ahead and have a div where I'm going to--
let me actually show the current score.
I'll say Score: this.state.score to say, all right, let's plug in the score
into this section of the page.
So now, OK, 1 plus 1-- a place to input the answer, and a score that's
currently 0,
What I'd like to do now is, when I type in a number and press Return,
for example, that's going to trigger submitting
my response as a potential answer.
And so, the input field--
there is no attribute of the input field that's like, when you press Return.
But there is onKeyPress--
like, press any key.
And so we're going to need to use that.
We're going to need to say, whenever a key is pressed, let's go ahead
and call a function.
We'll call it this.inputKeyPress.
But again, it could be called anything we want to.
And lets, inside of the inputKeyPress function, we'll take the event.
If I want to get what the key is that's actually pressed,
that's as simple as saying, event.key.
And so, if event.key is equal to enter, and JavaScript is a slight difference
between what double equal sign is and what triple equal sign is--
triple equal sign is going to do strict equality,
making sure things really match including the types of things.
And so, in general, it's safest to use triple equal side, if you can.
So I'm saying, if the key that I press is Enter,
then I want to go ahead and do something.
And so, one thing I could do is--
well, let me pose the question.
What do I want to do now?
Now that I've pressed Enter, and now I'm running
code that will run when I press Enter after typing in a potential number.
What should happen?
Check what?
AUDIENCE: Check if the answer is right.
SPEAKER 1: Check if the answer is right.
Great.
So I want to check if the answer is right.
And so, what is the answer?
What is the answer?
Well the answer is stored inside of this.state.response.
That is what it is that the user has typed in.
But of course, what the user is typed in is a string.
And so in order to turn it into an integer, in Python,
we just used a function called int.
In JavaScript, that happens to be called parseInt--
to say, take the string, parse it as an integer,
and save it inside of this variable called response.
And so now, what is the code for checking if I got the answer right?
What does that look like?
How do I know I got this addition problem right?
Yeah?
AUDIENCE: If answer equals [INAUDIBLE].
SPEAKER 1: Great.
I've gotten num1 and num2 here stored inside of the state.
So to check if I got the answer correct, I'm going to say,
if answer is equal to this.state.num1 plus this.state.num2.
I'm going to do something if the answer is right,
else I need to do something if the answer is wrong.
Questions about this much?
I've now verified whether the answer is right or wrong based on the state.
Yeah?
AUDIENCE: Does the program know that the values are numeric?
SPEAKER 1: Does the program know that the values are numeric?
No, it's possible that parseInt is going to get something that's not numeric.
And that's why we have to try and parse it first into an integer.
num1 and num2 are definitely going to be integer numbers.
Because we've said in this.state that they are, in fact, integers.
But the response, you're right, is a string.
All right.
So if the answer is right, we want to change the state.
And how would we want to change the state?
I'll go ahead and say state arrow, so that we can base it
off the previous state if we need to.
But what about the state needs to change if I got the answer correct?
Just in English, not necessarily in code.
Yeah?
AUDIENCE: The score [INAUDIBLE].
SPEAKER 1: The score.
Great.
So the score needs to change.
The score needs to become state.score plus one.
And the numbers need to change too.
I want to change what number one or number two
are so I can show a different question.
So num1 is going to be a new number.
And let me just go ahead and pick a random number.
And so, a common way that you'll see of generating random numbers--
most languages have a way of generating a random number between 0 and 1.
And in Python, the way to generate a random number--
or in JavaScript, to do that it's math.random.
That's going to generate a random number between 0 and 1.
If I multiply that by 10, that's going to generate
for me a random number between 0 and 10, non-inclusive on the upper bound
at least.
And so, if I want to generate-- take a potential floating point number,
like 2.8--
a decimal number between 0 and 10-- and convert it into an integer,
I'll either need to take the floor of that or the ceiling of that.
I'll go ahead and take the ceiling of that
in order to, say, if it was p make it 3, for example.
And so what I get by doing this is I get a random number between 1 and 10.
By taking a random number, multiplying it by 10,
and taking the ceiling of that--
that's a math trick you'll often see, where
you can generate a random number between 0 and 1,
and turn it into a random number in any range that you want to.
So this code is basically just saying, let num1
be some random number between 1 and 10.
And I'll go ahead and do the same thing for num2.
num2 is also just going to be some random number
in the range from 1 to 10.
Is there anything else about the state that needs to change?
Yeah?
AUDIENCE: You need to clear the response.
SPEAKER 1: Yeah, I need to clear the response.
And let's see what happens if I don't do that.
And then we'll actually go back and do it.
I'll go ahead and open up addition.html.
Here's the problem-- 1 plus 1.
I get the correct answer.
I'll type in 2, and press Return.
The problem changed.
My score increased.
But the two inside the input field are still there.
I'd ideally like to just clear it out when you get the question correct,
so that I can try typing in something else.
So in addition to updating the score, num1 and num2,
I'm also going to say a response is equal to the empty string--
clear out the response so that I can type something new in in this position.
So I'll refresh this page--
1 plus 1-- I type in a number, 2.
I get the question correct.
The score increases.
I get a new question.
I answer the question correctly, I get a new question and the score increases.
What should happen if I get a question wrong--
answer incorrectly?
Right now, nothing's happening.
What should happen?
What about the state needs to change?
Yeah?
AUDIENCE: The [INAUDIBLE] the score did not change [INAUDIBLE]..
SPEAKER 1: Sure.
Let's at least clear out the response, so that we can say, you know what?
If you get the question wrong, let's clear out the response
so that you can try again.
So now, if I have a question and I happen to get it wrong,
I type the incorrect answer.
The problems don't change.
The score doesn't change.
But at least the input field is now cleared out so
that I can actually type in something new again.
Questions about what we've done here so far?
Hopefully now you're starting to see the power that React
is going to give you in building user interfaces--
that we're able to update the score, that we're
able to have the problems change all without me having to say,
go into the DOM and actually change what's at these values--
no query selectors to try and grab things.
I just changed the state of the application,
the parts of the component that are going to change,
and the web page is going to update on its own via React
in order to reflect what it is that I want the page to look like.
Yeah?
AUDIENCE: If you want to save the state in a simple database
or save it so it's constant for the next user, is there an easy way
to do that with React?
SPEAKER 1: So if you wanted to save the state somewhere-- it
depends on where you want to save it.
So, if you want to save it on the client side
so that the next time you open up the page
it's still there, that you can use local storage for.
And we'll probably take a look at an example of that tomorrow.
If you want to save it on the server, then you're
going to need to send the data off to the server somehow.
And you can do that using an Ajax request like we
were talking about a couple of days ago, just to say,
send this data off to the server so that you can store it somewhere.
But yeah, you could do that.
Other things?
Yeah?
AUDIENCE: What happens now if you enter something other than a number?
SPEAKER 1: If I enter something other than a number--
So.
I type in "hi", for example, and press Return--
it's going to count that is incorrect.
Why does it count that is incorrect?
It's because, if I take parseInt and pass in a string like "hi",
what I get is a special JavaScript value called NAN, or not a number.
And NAN-- what I'm really going to be doing
is comparing whether that value is equal to, like, 1 plus 1, for example.
And that's always going to be false.
Because not a number is not going to be equal to any number.
And so, the if condition and the logic here
is going to handle dealing with non-numeric inputs for me.
Because answer is just never going to be equal to that sum
if answer is not a number.
But yeah.
Good question.
And good corner case to consider.
Yeah?
Oh I-- so yeah, if you look at the example online,
I add the square to num1 and num2.
That's to, if you wanted to update the game a little bit
to make it a little more difficult, such that every time you get a question
right the numbers get bigger--
if you take the score and add it to the numbers,
then you'll end up getting more difficult math questions
as the score gets higher.
But yeah, no need to do that.
Yep?
AUDIENCE: [INAUDIBLE]
SPEAKER 1: If you put in a single--
AUDIENCE: Character in response.
SPEAKER 1: Oh, just the letter A?
AUDIENCE: Yeah.
SPEAKER 1: No, that's still not going to be a number.
Because-- yeah, it's going to try and take the literal string
and treat it like a number.
And the character A, even though it has an Ascii value that
is a numeric value, the character itself is not
what we would generally consider to be a number.
Other questions?
All right, so let's try and do something a little bit different.
Let's try and now say, when you reach a certain score,
I would like to display some different methods.
Like, when I get to a score of 5, for example, let's
say, OK, you won the game.
So how might I go about doing that?
Well I don't actually need to add anything else to the state.
All I need to do here is to say--
all right, this render function--
instead of having it render the entire game,
let me just rename this function to renderProblem
for rendering a particular problem that I want to answer.
And let me go ahead and add another function called renderWin,
for example, that returns a div that--
we'll return it to h1.
"Congratulations, you win!"
So now I have two different functions-- renderProblem and renderWin.
And now in my actual render function, I can add logic to this.
Render doesn't just need to return something--
I can add any JavaScript logic I want.
I can say, if this.state.score is at least 5,
then go ahead and return renderWin.
Otherwise, if the score is not at least 5, let me return renderProblem.
So I've added some logic to the render function
known as conditional rendering.
Depending upon the value of the state, I can render different things
on the page.
And so what's that going to do?
By adding this simple logic, now--
Uh-oh, something's wrong.
"renderProblem is not defined".
Oh.
this.renderWin and this.renderProblem-- because they're
both methods inside of this component.
Refresh the page.
We get 1 plus 1.
And so the question correctly.
Answer the question correctly.
Correct, correct.
And when I get the 5th question correct, now suddenly
my score is going to be at least 5.
And the interface changes.
Nothing congratulations you win because we've
reached a different branching point in this conditional.
You get the question correct, and as a result,
we get a different output that gets displayed to the screen.
Yeah?
AUDIENCE: If you reload the page is that going to [INAUDIBLE]??
SPEAKER 1: As soon as you reload the page, in this instance,
we get reset back to the original state.
Because we're reloading the whole page, it's running the JavaScript again.
It's going to reconstruct all of my components,
and it's going to reset the state back to the original value of the state.
And so, as someone was mentioning before,
you could save the state in local storage--
and we'll probably see an example of that tomorrow--
if you wanted to retrieve it back later afterwards.
Yeah?
AUDIENCE: Is there a reason you always start with 1 plus 1
or could you start with a random number?
SPEAKER 1: If you wanted to, you could start with random numbers
other than 1 plus 1.
You'd just have to change the initial value of the state,
changing them to random numbers instead of having them initially be 1 and 1.
But yeah, you could do that too.
Yep?
AUDIENCE: So is it calling render whenever you change the state
or when it is calling render, how does it know to call render [INAUDIBLE]??
SPEAKER 1: So when React calls render is part
of React's abstraction, whereby it's going
to call render whenever it needs to.
And React is going to compute based upon the state when it needs to re-render.
And in particular, it's not even going to re-render everything.
It's only going to re-render the parts of the render's return value
that actually need to change.
And so, if I'm typing something into the input field,
the contents of the h1 that's displaying the problem-- something
plus something-- that's not changing.
And so React is not going to bother re rendering
that part, even though other parts of the application are changing.
And so React is going to be smart about it-- figuring out
which parts of the DOM need to be reloaded and re rendered in response
to the changing state of the application.
Other things?
Yeah?
AUDIENCE: [INAUDIBLE] file?
SPEAKER 1: Yes, you could definitely separate stuff into different files.
And in fact, tomorrow we'll probably take a look
at the more canonical way of doing things
like this, whereby we'll actually use a little bit of node
in order to do that too.
But more on that later.
Yeah?
AUDIENCE: You had the question go red when it was wrong.
Is that a set property of the state or [INAUDIBLE]??
SPEAKER 1: Oh, good question.
So in the application that I demonstrated a moment ago,
the original version--
when the question was wrong, I changed the color of the problem.
Like we changed it from just being black to being red text.
And so we could implement that feature here now.
In order to do that, whether or not the text is read,
that's an additional piece of the state.
That's something that the application state needs to know about.
And so I'll go ahead and add to this dot state
a key called "Incorrect" that is going to be equal to false.
I saw a couple of red frowny faces.
Questions before I go on?
All right, feel free to find me during project time
or ask questions later too, if you want to.
All right, so initially, we're going to say Incorrect is false,
meaning the problem is not incorrect.
And let me go ahead and say, here, if you get the question wrong,
let me set Incorrect to true, for example.
We'll change incorrect from false to true if we get it incorrect.
And now, what I'm going to do is take this h1--
the information that's displaying the problem--
and I'm going to give it a class name.
A class name is basically the same thing as what a class is in regular HTML.
But in React, we have to call it class name instead of class,
because class is already a keyword in React, or in JavaScript more
generally, that stands in for the class of the application.
And so I'm going to give this h1 a class name.
And in order to do this, I'm going to use some special JavaScript
syntax called the ternary operator.
The ternary operator is very common.
You'll see it in react a lot.
But basically, the idea of the ternary operator
is I say, I ask a Boolean expression question.
I add a question mark.
And then, I have a value for if the expression is true,
and then a value for if the expression is false.
And so, this is like a shorthand way of creating and if/else expression.
I basically just put a Boolean expression on the first hand side,
add a question mark, and then add two values--
a value if the expression evaluates to true,
and a value for if it evaluates to false.
And so I can say class name--
all right, if this.state.incorrect--
meaning, if inside the state I've gotten the question wrong,
let me go ahead and give the h1 a class name of incorrect.
But otherwise if I didn't get it incorrect then,
it doesn't need a class name.
So I'll just go ahead and put two double quotes, meaning empty string--
no class name here.
And so now, only if the problem is incorrect,
then h1 is going to have a class of incorrect.
And so now, up in this header, I can just do normal CSS code.
I can add some style code that says, if something has a class of incorrect,
then go ahead and color it red.
And so now, by adding style for what should
happen if you have a class of incorrect, and by adding to this h1
a class name that is only going to be incorrect if I've actually
gotten the question wrong.
Now when I load this page, I type in the answer, I get it right.
I type an answer and I get it wrong, the color changes to red.
Because it's gotten that new class of incorrect.
There is a small bug here.
Anyone catch what the bug might be based on the code that I've written?
Yeah?
AUDIENCE: [INAUDIBLE]
SPEAKER 1: Will it switch back?
Will it?
I type 15, I get the answer correct.
And no, I get a new problem.
But the colored didn't switch back.
And that's because I need to additionally
say, down here, if I get the question right,
well then, I better set incorrect equal to false
so that it goes back to having a color pf black afterwards.
So I'll try again.
I get the question right.
I get the question wrong, and I get the question right,
it changes back from red to black.
By changing the value of the state, the interface updates automatically.
What questions you have?
All right.
In that case, what I thought we'd do is, I'll
help get you started on what's going to be the morning project.
And one of the canonical things to do with React when you first try to do it
is to try and create a to-do list application--
an application where you can just add tasks and remove tasks from them.
And so we'll go ahead and give that a try.
In order to do that, there are a couple of useful JavaScript tips and tricks
that you might want to take advantage of.
So recall that when you have application state,
you should never change state directly.
You should never say, this.state.whatever,
something equals something else in order to change the state directly.
You should always be calling this.setState.
But if you wanted to manipulate the state
without changing the original state, you might want to create a copy of a list.
And so, this is something that's probably going to come up.
So I'll show it to you now.
If I have a list of things, like list1 equals 1, 2, 3, 4, 5,
and I want to make a copy of that list so that I can manipulate that copy,
you can do something like this.
The dot dot dot list1 is basically saying, fill in list1 into this list.
And so, copy is also going to be a list, 1, 2, 3, 4, 5.
But it's going to be a copy of that list.
And we'll see in a moment why that might be helpful.
If I wanted to make a copy of the list and add something to the end of it,
well then it's as simple as syntax like this.
list1 is 1, 2, 3, 4, 5.
list2 is fill in all of list1 here, and then add the number 6.
And you can imagine this might be useful if, for instance, you're
building a to-do list application.
You have a list of things to do, and you want to add on one more thing
to do at the end, for example.
You've got a whole list, and you want to tack on something at the end of it.
So that might be useful as well.
You might also want to delete something from a list.
And in order to remove something from a list,
one easy way to do that in JavaScript is the splice method.
And so, if I have list1--
1, 2, 3, 4, 5--
and I say, list1.splice, and then 3 comma 1, what that's saying is,
pull out elements starting at index 3.
That's the first argument.
And the second argument is how many things should I pull out of that list.
And so here I'm saying, from index 3 in the array, which is the number
4, go ahead and remove one element.
And so now we get 1 2, 3, 5.
So just a couple of little tips and tricks for interacting with JavaScript
lists, since it's a syntax you probably haven't seen before,
but that's ultimately going to be helpful.
So let's go ahead and get started with this to-do list application.
I'll go ahead and create a new file.
We'll call it todo.html.
I'll go ahead and copy the contents of hello just to get us started.
The title will be todo.
And we'll delete the hello component.
We don't really need it.
And OK, here's our application.
Constructor, props.
What is the state of our to-do list application?
What are the things we need to keep track of?
Yeah?
AUDIENCE: [INAUDIBLE] do you use setState and append to a list?
Like if you had this [INAUDIBLE]?
SPEAKER 1: If you wanted to append something to a list
by setting the state, you should do it this way--
by making a copy of the original list, and then adding something
to the end of it.
And that's, again, for security reasons--
for the race condition issue that I mentioned before--
that you want to make a copy of the state
instead of actually modifying the state directly.
OK, a to-do list application--
what do I need to keep track of?
And I'll show you what the finished product should look like,
in case that helps.
We'll just create something looks a little something like this.
We've got tasks, a window bar that shows you how many tasks do you have.
You add a thing to do, add that as another task.
Pet otter, add that as another task.
So we've got this growing list of tasks.
And if you want to, you can add the support
for deleting them, checking them off.
So what is the state of the application?
What things can change?
AUDIENCE: [INAUDIBLE]
SPEAKER 1: The tasks.
Yeah, all the tasks themselves.
That's going to start out just being an empty array.
There are no tasks to begin with.
And what else?
There's one other piece of the state.
What else changes here?
Yeah?
AUDIENCE: Whether they're complete or not.
SPEAKER 1: Whether they're complete or not.
Sure.
You could implement it by keeping track of whether the task is complete or not.
You could also implement it just by removing the task from the list
if it's complete, since it's not going to come back.
So certainly, that's something you could add if you wanted to.
AUDIENCE: Input.
SPEAKER 1: The input field.
Great.
This is something that changes.
When I start typing, the value of the input field changes.
And so I'll go ahead and give it an input that, at least
initially, is going to be blank.
What is the render function going to do?
Well, let's go ahead and render an h1 that just says Tasks, for example,
and an unordered list where I'm just going to list all of the tasks.
And so how am I going to do that?
Let me just go ahead and, for sake of example,
start us off with a couple of tasks, like thing1, thing2, thing3,
in terms of things to do.
If I want to create one list item for every single thing in this.state.tasks,
well then we can go back to functional programming,
which we introduced a couple of days ago, and recall that if I--
what I want to insert here is going to be this.state.tasks,
and then I can say, .map
Remember, map is a function that takes an array,
and goes over every element in the array,
and lets me apply some function to it.
And so I'm going to map over here.
And we're going to map over and take every task, and we're going to--
I'll go ahead and fix the spacing a little bit.
And for every task, we're going to go ahead and return some list item.
And that list item, at least for now, we'll just go ahead and say, let's
print out the task there.
So long story short, we have an unordered list.
And we're going to take inside this unordered list,
go over this.state.tasks, mapping over it, going one task at a time.
And for each task, we're going to go ahead and print out
a list item that's going to be equal to whatever the value of the task is.
Let me go ahead and open up todo.html now,
so we can see what that looks like.
All right, great.
Now we have tasks, and we have this loop that's going over,
creating one list item for each element.
Yeah?
AUDIENCE: Could you do a for loop?
SPEAKER 1: You could also do a for loop in order to do this same thing.
So you'd do a for loop to sort of add to this growing string, for instance,
and then insert that string into the HTML page.
You could do that too.
One error you'll notice here-- and this is just a nuance of React that might be
worth solving--
is, you get a warning if you do something
like this, which is that each child in an array or iterator
should have a unique key prop.
And basically, all this is saying is that, if you are looping over something
and creating a whole bunch of elements, React
would like you to give all of them a unique property called key.
And it does this for efficiency sake.
So that if you're updating only one element in the list,
it doesn't need to also update all the other elements.
It can just update the one in question.
And so, we'll give this a unique key.
The task name might not necessarily be unique.
But an additional feature of map is that it can loop over all the tasks.
But you can also give this function the optional argument, i for index,
that will let you access which index into the array is this right now.
And so, I'll go ahead and give this a key
of i, meaning the first one will be task 0, then 1, then 2, so forth.
Yes?
AUDIENCE: [INAUDIBLE]
SPEAKER 1: So if you start splicing the array, the indices will be the same.
But React is going to be smart enough to know that,
because the element at that index has changed, that it's still going
to be able to re-render it correctly.
OK, so if you do that, just add key equals i to it.
Then when you refresh it, you'll get rid of that warning.
So all right, great.
We've gotten this list of tasks now.
We're also going to want an input field underneath this list of tasks,
whereby I can have an input field that is going to have a value
of this.state.input, and probably also a button--
and I'll actually put all this inside of a div--
and a button called Add Task
So I have an input field whose value is whatever the current value of the input
is, and also a button that's going to add a new task for me.
I refresh this page.
And all right, now I have an input field,
and I have a button to add tasks.
But much like with the addition game example,
if I start trying to type a task here, nothing shows up on the screen.
Because I actually need to add, in the same as before,
an onChange handler to say, when I change the value of the input field,
call the handle change function.
And OK, what does handle change going to do?
Well, it's going to be a function that just sets the state the function needs
to take the event as its argument.
And we're going to set the state.
And the new value of the input is the event.target.value.
Same as before-- when I make a change to the input field,
update the input value inside of my state currently.
So I refresh this, and now I can actually
type a new task into the task page.
Clicking Add Task, of course, doesn't really do anything just yet.
So let's make it do something.
Button onClick-- let's go ahead and run a function called this.addTask,
for example, for when you click on a button.
addTask is going to go ahead and be a function.
And we're probably going to want to update the state somehow here.
Set the state to be something new.
I'll go ahead and do this.setState.
It's going to take the original state as its input.
And the new state is going to be what?
What should the new tasks be?
Yeah?
AUDIENCE: [INAUDIBLE] input.
SPEAKER 1: Great.
It's going to be whatever the current list is-- state.tasks--
and then state.input, which is whatever it is that I've currently
typed into the text field.
So I'm updating the state, adding that task.
I'll go ahead and remove these sample tasks so
that we can get started with something.
Go ahead and refresh the page.
So tasks-- I can type task1 here, add the task,
and all right, task1 shows up.
Granted, it stayed here in the text field,
but that's something we can fix later too.
I type in a second task, click Add Task, and all right.
That task is added to the list as well.
Questions about what we've done here so far?
All right.
In that case, I'll post a distribution code in just a moment.
But we'll go ahead and break for our morning project.
Here we'll create the to-do list app.
We're going to allow the user to type in a task,
add a new task to a list of tasks, and delete tasks
by clicking a button next to each task.
I'll give you a suggestion of the order in which to do things.
I'll post a distribution code in a moment,
if you'd like to take a look at it and use that as a reference point.
I'd start by just displaying on screen the current number of tasks.
See if you can figure out a way to, on the application,
get the page to draw information from the state to display, like,
you currently have four tasks in your task list, for example,
and display that information.
Once you get that working, go ahead and see
if you can clear out the input field after we add a new task.
So you type something in, you press add task,
and the input field clears out so that you can type in a new task.
The thing to do after that is going to be,
let's take each task in the task list.
In addition to just displaying the task, also
display a button next to it with maybe an X or a checkmark to say,
completing this task.
And just add that button there so that every list item has a button with it.
And then finally, as a final challenge, if you're up for it,
make it such that when you click on that button,
that actually triggers changing the state so that we remove
that task from the list of tasks, therefore
allowing you to complete and add new tasks to your task application.
If you'd like to, feel free to add other features as well.
Or feel free to take the game from earlier this morning
and add features to that too as part of the morning project.
We'll go ahead and all just stay in this room for this morning.
And we'll go until 12:30, and then break for lunch then, and reconvene at 2:00.