[MUSIC PLAYING]
JORDAN HAYASHI: Hello, and welcome for Lecture Two--
React, Props, and State.
So last week, we talked about a bunch of different topics, one being ES6
and beyond and the syntax that comes with each of those.
We talked about closures, the process by which
a function can reference variables declared in a parent function.
We talked about IIFEs, Immediately Invoked Function Expressions.
We talked about using functions as first-class citizens.
We talked about the execution stack and event loop,
and how JavaScript actually executes in browsers.
We talked about callbacks, promises, and async/await, all of the different ways
to handle asynchronous actions.
And last, we talked about this and the way that this is bound.
This week, we're going to start with classes, which
is a syntax I was introduced in ES6.
It simplifies the defining of complex objects that have their own prototypes.
And with that, you have two different things.
You have classes and instances.
Classes is basically an abstract thing that you can declare,
basically saying, hey, by the way, any of these objects
that you create will have these methods associated with them.
Or they might have these things attached to them that you can use.
And then when you actually turn an abstract class
into an instance of that object, that is called an instance.
An example of that would be the difference between the date,
which is a function-- it's a class--
or a new date.
So if you do something like const d equals new date,
then now you have a date object itself.
And so Date with a capital D would be a class in that case,
and the lowercase D would be an instance.
These instances have things attached to them, like methods and properties,
and the classes have things like static methods.
And so methods are basically anything that's
a function that can be invoked on any of the instances.
You can think of that as a function on the classes prototype.
A static method, on the other hand, is basically
a method that doesn't really care about the particular instance of a class.
Instead, it cares about all instances of the class, so something like Date.now,
where you don't really care about a specific instance of a date
if you just want to get the time.
Whereas something like turning a date to a string--
in this class, d.toString--
in that case, you do care about the particular date
object that you're working on.
And so when you do capital Date.now, that's
considered a static method, since it's attached to the class.
And if you do something like date--
lowercase d-- dot toString, that really matters which instance you're attached
to, and therefore, that's a method.
Lastly, we have properties, which are like methods.
But rather than being functions, they're actually just values,
and they are associated with a particular instance of a class.
And so with classes come a few different keywords.
We have new, which you saw me type over here, which is basically saying,
hey, give me an instance of this particular class.
You invoke the class like an object, in case you want to pass anything into it.
And so say we want to do new const d2 equals new date,
and we actually want to pass in some number.
That gives us a new date from a very long time ago.
So d.toString.
Oh, d2.toString.
Since we passed in the number 1, 2, 3, 4, that's basically saying,
give me a date that's 1,234 milliseconds after date 0, which is back in 1969.
So a constructor is basically something that you
define within a class that says, hey, when you create a new class,
invoke this method such that you create a new instance of a class.
So let's actually practice this a little bit.
So is everybody here familiar with a data structure called a set?
So basically what a set is, is it's a list,
a data structure that supports things like add, delete, and inclusion,
where you cannot have multiple things of the same value.
Or in other words, it's a list of unique values.
And the methods that it should support are
add, which is basically add to this list;
delete, which is basically get rid of something from this;
or inclusion, which is saying, hey, does this list have a particular value?
And it should also have the ability to get its size.
And so down at the bottom of the file, I defined a few tests
that we're going to run after we implement this, such as line 7 here,
we have const s gets a new set with an array from 1 to 5,
which is basically saying, give me a new set with five values, 1, 2, 3, 4,
and 5.
We're going to try to do S.add1, and so we're
going to try to add 1 three times to the set.
And when we do S.size, we want it actually to only have five members,
because you shouldn't be able to add 1 multiple times.
Down here, we do S.add6, and then we try S.has6,
and it should contain the number 6.
That thing should not be there.
We try to see the size of it, and it should have added another member.
And then down here, we tried to delete that and do a couple
of associated checks with that.
And so how are we going to go about implementing this class?
So as per the slide over here, we use a method called constructor
in order to go ahead and construct an instance of this class.
And so within the class, we should have a method called constructor,
which takes a single argument.
It should take an array or some sort of list to be created with.
And what are we going to do?
Well, we should attach to the instance the array.
And that's basically saying, when I'm constructed,
I expect to have one argument, which is just an array.
And the only thing I'm going to do when creating this set object
is just store a reference to that array.
By doing this.arr = arr.
And so in this case, the this keyword is referring
to the instance of the object.
Cool, so let's try adding a couple of different methods to this.
So we should be able to support add, which should take a value.
We should be able to support delete, which also takes a value.
And we should have something called has, which checks for inclusion.
So how might we do something?
How might we add to this class?
Does anybody have any ideas?
AUDIENCE: [INAUDIBLE]
JORDAN HAYASHI: Exactly.
So we should use something like push to add to the array.
But before we do that, we should make sure that that number does not already
exist.
And so maybe we should implement the has method first, which is a great idea.
Let's go ahead and do that.
So how might we do has?
Well, it turns out on the array prototype,
we already have something called includes, which tells us
if an array includes a value, so we can just do that.
We can do return this.arr.includes(val).
And so now that we have that, how might we take care of add?
We should say, oh, well, if this does not have the value already, add to it.
And so here I use this.has.
So this here is referring to the instance of the set,
and so this.has is referring to this method
down here, on this particular instance.
And then when I do this.arr, this still refers to the instance of this set.
And so we're just getting at this array property that we have,
and we're pushing that value to that array.
Cool.
So how might we go about this delete?
AUDIENCE: [INAUDIBLE] has value.
JORDAN HAYASHI: Yeah, we can check if we have the value,
but it doesn't really matter all that much.
A quick and easy way would just be doing this.arr = this.arr.filter
and then we can just filter by the values.
So we could say, oh, we want for every x in here,
we want the x's that don't equal this value.
Cool.
And so we can go ahead and run this to see if it works.
Oops.
While I edit, I should flip these.
And we go ahead.
S should have five members and actually has-- ooh, we forgot to influence size,
actually.
And so we took care of all of the methods,
but we didn't include the size.
And so we should be able to return the size of this set.
How might we do that?
Well, this is interesting.
So we should be able to get at this value by doing the instance.size.
And JavaScript actually has a convenient way.
We can do get size, which is saying, when
somebody tries to get at the value or the property.size,
actually run this function.
So this is just syntax for that shortcut.
So how might we implement size?
AUDIENCE: [INAUDIBLE]
JORDAN HAYASHI: Yeah, just return this.arr.length.
So now we can run this, and we see I should have five members,
and it actually has five.
So that's good.
S should contain 5.
That's true.
That works.
S should contain six.
It's true.
S should have six members, and actually has six, so we're good still.
S should no longer contain six.
That also returns true.
And lastly, S should have five members, and actually does indeed have five.
So does anybody have any questions with our implementation of set as a class?
Great.
So it turns out JavaScript actually already has a set class,
and it works exactly as we implemented.
But say we actually wanted to use the native implementation of set
and actually add some stuff to it.
So that's where we use these other keywords, called extends and super.
So extends is the JavaScript way of saying,
hey, I want to start with a base class and actually add to it.
Extend this class.
And super, as we'll see in a second, is when we're writing that class,
so we can refer to the original class using this keyword.
And so in this example called my set, we're
going ahead and extending that set with a bunch of different things.
And so here you see constructor.
It still takes an array.
And the first thing that we do is we invoke super on that array.
So this is basically saying, hey, we're extending a set.
So when you do the constructor, the first thing you should do
is actually run the original set's constructor.
And then let's also keep track of this.originalarray
is the array that's passed in.
And so we'll use that later to use this thing called reset.
And so say we wanted to every single time we added a value to this set,
we also wanted to log, hey, we added a value to this set.
So we can just start writing this method called add.
It takes a value just like any other example.
But instead of implementing add ourself, we're
just going to use the native implementation of add.
And so that's where we use super.add.
So super, again, refers to the class that we're extending.
And so when we invoke super.add, it goes ahead
and does that using the native implementation.
And then since we're going to extend it with some additional logging.
We're just going to log, hey, we added this val to the set.
And if you're not familiar with this, if you use the backticks,
you can go ahead and add variables in line, in the string,
and it'll go ahead and substitute those in.
And so you see we added a couple of other methods here.
We have to array, which is basically saying, hey, I actually want the array,
and not the set.
And so we can just return Array.from (this).
We're passing in the entire instance.
And lastly, we have a reset, which is saying, hey,
I want the original set that I had, or at least
a new set with equivalent value.
So you can return a new my set.
So notice you are referencing my set inside that class.
We want a new one, and we're going to pass in,
as the array here, the original array.
So this is an example of us extending a class that already exists.
And as you see, if we want to reference methods on that original,
we just use that super keyword.
So any questions on sets, how we define them--
or sorry, classes and how we define them, how we extend them?
So why might this be useful?
So as you guys are doing on your project,
you're keeping track of these things called to dos.
What if we actually had a class for to do?
And when you invoke this constructor on some configuration object,
what if it pulls out the text and whether it's checked or not
and stores it as part of [? its ?] class instance?
And say we want to render it to the page.
What if we could just return some HTML like this?
It would be quite handy, right?
And that actually is our next topic, react.
So react is a JavaScript library, and it allows
us to write declarative views that will react to changes in data automatically.
It allows us to abstract complex problems into smaller components,
and it allows us to write simple code that still perform it.
And so I use this word in the first bullet, declarative.
So what the heck does that mean?
So in CS50, we learned a paradigm of coding called imperative.
And today we're going to talk about declarative coding.
So the difference in imperative and declarative
is like asking the difference between how you do something
and actually what you want out of it.
So imperative programming outlines a series of steps
to get to what you want, whereas declarative,
you just say what you want.
And it's just an implementation detail on how to get it.
And so we've learned a few different languages through CS50 in this course.
A couple that come to mind are HTML and JavaScript.
So in HTML, do we tell the browser exactly how
we want to render all of these things?
Do we tell it exactly how we want the DOM to be constructed?
No, we just tell it what we want.
And so HTML is considered a declarative language, because you just say,
hey, I want this.
And browsers are in charge of just giving you what you want.
Rather, with JavaScript, as you'll see in your first project, when
you want to do anything to the DOM with JavaScript,
you tell it, oh, first get me a new element.
Call it a div.
Then do this.
Then maybe append it to the tree.
Then maybe add a class to it.
Maybe give it some inner HTML.
And so you're telling it exactly what you want and how to do it.
And so that is the more imperative way of programming.
So let's take this into an example.
Say we had a classical guitar here, and say we
wanted to actually create this guitar.
So in an imperative way, how would you describe that?
Well, you would say, oh, I need a head over here.
I need to add some pegs to it.
Maybe I want the neck.
Maybe I add some frets to that.
Oh, I need to create the body and attach them all and then maybe return that.
And what would be a more declarative way of creating the guitar?
You just say, I want a guitar.
Maybe tune the strings to this.
And so an example in pseudo code would be like this.
So say we have a guitar, and say we have some function
called create element, similar to what we have in the document in HTML.
And say we know exactly what strings we want.
How might we go about creating this guitar?
Well, first we might want to do something like let's create a head.
Again, telling whoever's listening exactly what we want.
And then maybe for 6 pegs, maybe we want to start adding pegs to that head.
And so now we, in a very terse manner, have a head with six pegs.
And so we might do the exact same thing with neck.
And maybe we want to add something like 19 frets.
And you can see how this gets a little bit annoying to write it, right?
And maybe we do the same thing with body,
but we have some sort of for each loop with the strings,
and we pass in the tone that we want.
And then we go ahead and create a string and tune it to that tone.
And then we go ahead and add that to the body.
And you see how this gets very step-by-step, exactly what we
want to do to create a guitar.
And this is exactly what we've been doing thus far for writing to the DOM.
And so how might we do this in a more declarative manner?
Well, we would just say, give me a guitar.
Give me a string.
Maybe I want it to be tuned to the first note in the string.
And maybe copy that a few times.
And there we go.
A better way to do this would be rather than hard coding these,
maybe we just do strings.map, and for each note, we stick it in there.
So it looks like there's a little bug here.
I used string even though I declared the variable called strings.
So if we map over the array called strings,
and for each note return a string where the note is note,
then we have declaratively written a guitar.
Does this make sense?
So a great thing about react is that the way that you code
is in a very, very declarative manner.
The browser APIs aren't super fun to work with.
You get to work with them a bit in project zero, but react just
allows us to write exactly what we want.
And the library will actually take care of the DOM manipulation for us.
And so what does that really look like?
So say we wanted to create a slide here.
Say we wanted to use the native DOM manipulation
API in order to create the slide here.
So we might have a slide element that we created
and say we wanted to add a H1 to that.
Add a title to it.
How might we do it?
Well, we'd have to do something like const title = document.createElement.
Get an H1.
And then start adding to that.
We can do title.innerHTML is equal to the SLIDE.title.
And you see how this starts getting to like what we've been doing earlier,
where you say exactly what you want, but it might take you a long time to do.
So in react land, this is actually a lot easier.
So how might we do this if we were doing this completely declaratively?
Well, we just say exactly what we want.
We want a slide.
Maybe it has a title, where the title is equal to the slide's title.
Maybe we have some bullets.
Or we can just map through the bullets that we have up there.
We can do SLIDE.bullets.map.
And we can say for every bullet, just give me a list item.
And maybe we should wrap those list items in unordered list.
And maybe instead of using this, we can do an H1 here.
So see how this is a lot more declarative?
Makes sense, right?
It just makes sense.
It's easier to read, and it's easier to maintain.
So another great thing about react is it's very easily componentized.
What do I mean by componentized?
Well, it's a process by which you break a very complex problem into a bunch
of different, discrete components.
You can reuse these components, which is great for consistency.
So say you had a bunch of slides, and you wanted
to just change how every title looked.
Well, if you did this using native DOM manipulation,
that might be a bunch of different lines of code that you have to change.
But if you did this using React components,
it might just be one line that you have to change,
and then it's applied to every single slide that you have.
It's also great for iteration speed, because then you
can just reuse the components over and over,
rather than having to cut and paste code all over the place.
Another great thing about these components
is that React's declarative nature makes it very easy to customize components.
So say we had the last three slides and wanted to write them in HTML.
It might look like something like this, where
you have a div, which represents a slide where the titles react.
You notice these are the same three bullets as previously.
We have the declarative slide, where we have the same bullets as previously.
And say we wanted to change this.
Say we wanted to make all of the titles have a slightly different style.
Well, how might we do that?
Well, we'd have to edit this line.
We'd have to go edit this line.
Maybe down there, there's another title that we have to change.
Or what if we wanted to even change the structure of how we represent bullets?
Maybe rather than using an unordered list,
we might use an unordered list with a div that wraps the list items.
Well, in order to do that, that would be a lot of code you have to change.
But imagine that we had broken this up into a bunch of different components.
Where might it make sense to break it up?
Well, you see us repeating code that looks pretty much the same
over here, right?
So maybe that should be broken up into a separate component.
So how might we go about doing that?
Well, first we have to extract the information, and so in this array here,
we have the slides where I've basically just ripped
out the information for each slide.
And so now let's go ahead and implement that slideshow.
And so in order to do that, we might have
something like where we have a slide, which might take an array,
or it might take an object.
Let's call it a slide.
And what will it return?
Well, it should return a div.
Maybe inside it we have that H1.
Then maybe we have that unordered list.
And then go ahead and close that div.
So what goes in the H1 here?
Well, maybe we should have that slide's title.
And what about generating those bullets?
Well, like we did in the previous example,
we might want to do the slide.bullets and map [? overflows ?]
to create those list items.
So for each bullet, just go ahead and create a list item
where you have that bullet.
And so now we declared exactly what a slide is.
Well, a slide takes in an object representing
the slide in the same shape of the object up here.
And then it just returns the same HTML that we had in the other example.
It's a div that wraps in H1, where we stick
in the title, an unordered list that has some list
items that represent those bullets.
And now how might we create that slideshow?
Well, maybe we just do for each slot in the slides,
maybe we have an outer-wrapping div that maps through the slides.
And for each slide, we actually just use the slide down there.
So now we're going to get ahead and use React and generate
basically the same HTML as we had in the previous one.
But now say we wanted to change the styling of the title.
How would we do that?
Well, that's just right here.
What about if we wanted to change the structure of how
we created those bullets?
In the previous example, if we wanted to wrap the list items in a div,
it would be many, many lines of code.
But here, it's just you stick a div here,
because this is basically an abstract component that says,
if we wanted to create a slide, here's exactly how we do it.
Just make sure to pass me a slide of the correct shape.
And so the React paradigm is to take a very complex problem
and break it down into small chunks like this
that each solve a discrete problem in that UI.
Any questions so far?
Cool.
So another great thing is that React is very performant.
We just write what we want, and React will
do the hard work of playing with the DOM,
or changing things so that what we have written
matches with what we have showing on the page.
And so the way it does this is through an algorithm called reconciliation.
And this is the process by which React syncs any changes in app state
to the DOM.
So what's great about React is that it actually
maintains what's called a virtual DOM.
And so the slow thing about playing with the DOM
is that anytime you destroy elements or create new elements, that
takes a relatively long amount of time.
And so the way that React says, maybe we should do this
better by rather than changing stuff in the DOM
every time we want to change something, what if we just stored everything
in memory?
And then with any changes, we can just say,
hey, how does this differ from what's shown on the page?
And only change what's necessary.
And so that's what's done in the reconciliation process.
So first, anytime your data changes, React
will reconstruct that virtual DOM.
Then it will diff that DOM against what's actually there in the real DOM.
And it'll make only the changes that are needed.
Of course, there is an asterisk that goes along with that,
but in your mental model, you can just think of it
as React will just only make the changes as necessary.
So how the heck do we write React?
Well, there's this thing called JSX, which
is short for JavaScript and XML, which is basically just an XML-like syntax
extension of JavaScript.
It's great because it just transpiles directly to JavaScript.
So as we talked about in an earlier lecture,
the paradigm now is to rather than just writing JavaScript by hand, using ES5
directly, we can write in these other languages
that just transpile back to JavaScript.
So JSX is an extension to that JavaScript syntax, which will just
compile back down into JavaScript.
And so tags defined in JSX, XML looks exactly like HTML with the tags.
Lowercase tags are treated as HTML or SVG tags,
whereas things uppercase are treated as our custom components.
And what the heck is a component?
Well, a component is just a function, a function that returns a node.
What's a node?
It's something that React can render.
For example, like a div or a span or a string or a number.
And components will receive an object of properties
that are passed to this element.
So going back to the example that we were doing before,
see how one, we declared a const called slide down here.
And notice how I uppercased that S. That was
fully intentional, because in JSX, a tag with a capital S gets
invoked like a function.
And what does it get invoked with?
Well, anything you pass it as properties.
So if you remember properties from HTML, you just
pass them in line with the key and a value pair.
In React, you do the exact same thing, and it actually
gets passed as an object to the component that you described.
And so now to talk about props.
Well, props are just past as an object through a component
and used to compute the return node.
So basically, the object that we were just referring to in this example,
we called it a slide.
In React convention, we always call that props, short for properties,
like those HTML properties.
And any change to these props will cause a recomputation of that return node,
or in React vocab, a re-render.
And so unlike in HTML, these can be any JavaScript value.
So if you remember back to HTML, when you declare a property,
it has to be a string.
It might be JavaScript, like a JavaScript function,
but really it's just a string.
And so you can't pass any complex objects or a date, object, classes,
instances, and stuff like that.
But in React, we can pass anything.
So notice here, slide is an object as declared in the array
that we have up there.
And we're just passing the object over there.
And the way that we pass values in JavaScript
is we wrap them in single curlies, which means,
hey, execute this as a JavaScript.
Does that makes sense?
So let's actually use a live example of this.
So there's this website called codesandbox.io,
which is linked on the website in the Resources tab,
and this allows us to write React and actually render it live.
And so can everybody read this?
So basically, what's on the left over there is code that gets executed
and runs live on the right side here.
So if we started editing this, you see it applied directly on the right side
there.
And so you see we have a const called app,
which doesn't care about any arguments it
receives and just renders the static HTML here.
So what if we actually wanted to pass it a prop?
So say we passed it something like a count and passed it the number 1.
Again, we use curly braces there to represent this is JavaScript coming,
and the JavaScript is just the number 1.
So how might we go ahead and render that in the app?
Well, first, we need to actually pay attention to the object
that we receive here.
And second, we can just do it directly in line.
And so we use those curly braces to represent,
hey, here comes some JavaScript.
And we can just use props.count, and now we'll
go ahead and grab the prop with the key [? call ?] account.
And so I mentioned that as props change, React gets re-rendered.
So how might we do that?
Well, we can just wrap this in a set timeout, or a set interval, rather.
And every 1,000 milliseconds or 1,000 milliseconds,
let's go ahead and pass it not just one, but the count plus plus,
where count starts at 0.
And every time this is invoked, it increments.
And so down here, we're saying, sudden interval,
which means run some function every n seconds.
We set n to equal 1,000 milliseconds, or one second there.
And every time we want to render this function
called app with a count of one more than it was last time.
And so we start at 0, and every second you
see we pass a new prop count incremented.
And even though we're not really doing anything actively in the app here,
we wrote this in a very declarative nature, right?
We said, for any props that you give me, just render a div with an H2 where
the H2 is the value of the props.
See how that's very declarative.
We don't say, oh, first you have to grab the count,
then check to see if it is different than the last one,
and then append this to the DOM.
We just say, hey, this is what we want.
And React will give it to us.
Any questions on React or props thus far?
Yeah?
AUDIENCE: [INAUDIBLE]
JORDAN HAYASHI: Yes, of course.
So set interval requires two arguments, where the first one is a function.
So the question was can you go over the arrow notation here?
And so set interval expects two arguments.
One is a function that it will invoke with no arguments,
and so I'm just declaring an anonymous function here with no arguments.
So I'm saying, here is a function that takes no arguments,
and what should I do?
Well, I should render this.
I could have also written this as this, and it would have functionally
been the exact same.
Does that makes sense?
Any other questions on React or props?
Yeah?
AUDIENCE: So in line 10 [INAUDIBLE]?
JORDAN HAYASHI: So in line 10, we have braces after the arrow here.
So that's just saying, interpret all of this as one statement.
So something special about arrow notation
is that it has an implicit return, which means we don't actually
have to write-- so we could have written the same thing as this,
as a function that takes props.
And what does it do?
It returns this.
So this actually does the exact same thing.
So we're saying, app two is a function that
takes a single argument called props.
And what we do is we return this, and so arrow notation shorthand is just
you have your arguments in arrow.
And then if you don't have braces, which referred to it like a code block,
it just returns whatever's next.
And so we're saying, return this.
What is this?
Well, it's this div and H2.
We're going to wrap it in a parentheses so we know that it's just one value.
Does that make sense?
A great question.
Do you guys see how these are the same?
So this is great, but we don't really have all that much power yet, right?
If we wanted to go ahead and change these props,
we still have to drop down to this raw JavaScript over here.
So next we'll see exactly how we create apps that are stateful.
What does that mean?
Well, there's this notion of state in React,
and state is basically an internally managed configuration
for any component.
And so now components become classes, and this .state is a property on that
component's instance.
So how do we update the state?
Well, there's a method called this.setState,
which is implemented in this thing called a React.Component, which
we have to extend in order to have access to that method.
And this goes ahead and changes that value.
So you can pass an object to be merged or a function of the previous state.
And so if we pass this.setState, an object,
it will go ahead and merge that in with the existing state.
So if we pass it in an updater function, it's
basically a function that gets run when we want to change the state.
And the set state calls are batched and run asynchronously.
And of course, any change in state will also cause a re-render,
because it would be silly if we were to change the state
but not reflect that in the UI.
And so how might we go about representing state over here?
So first, let me copy this so that we can save it.
So let's go ahead, and rather than having an app be a function,
let's actually have it be a class.
So we can do class app, and we want to extend React.Component.
And within that, we want to have this method called render, which is
automatically invoked on a re-render.
Within render, we want to return this.
Cool.
So the way to now write this is rather than having
app be a function that takes props and returns something,
we're actually writing a class for app.
And so as we talked about earlier, classes have instances.
And React knows that when you want to render something
like this, if it's a class, go ahead and create a new instance of that
and pass in these as props.
And notice how we don't ever take the props anywhere.
That's because when we extend React Component,
React Component, that base class, goes ahead and attaches the props
to the instance.
And so in order to get at them, rather than doing props does something,
we do this dot props dot count.
So again, the props that come in, in the way that React.Component
is implemented, it automatically takes the props
and attaches it to that instance of the class.
And so in order for us to get them in the render method,
we do this dot props dot count.
Does that make sense so far, going from a function to a class?
We'll talk about this in depth the next lecture.
And so we talked about this thing called state,
and how do we actually go ahead and use that?
Well, when we want to create our state, we actually
do that in the constructor method.
And so the first thing that we want to do in our constructor method
is actually called a super, which means allow
React.Component to do stuff with the props
that it would have done otherwise.
And now go ahead and do what we want to do.
What do we want to do?
Well, we want to initialize this thing called state.
Cool.
So now we have this thing called state, and how are we
going to go ahead and update it?
Well, maybe we should have something called increase count, which
is a method on this instance.
And let's go ahead and increase the count here.
So how might I do that?
Well, I should call this dot set state and pass in count is this dot state dot
count plus 1.
And so now we have a method on this instance called increase count
that we can call.
And it should, in theory, increase that count.
And so rather than referencing the props down here, let's reference state.
And now it should be 0, and it's just going
to stay at 0, because we're not doing anything.
So we can go ahead and get rid of this interval.
And so how are we going to change that value of 0 to be something like 1?
We have to invoke that method, and so let's go ahead
and do that when we click a button.
So let's have something like div here, and within that div,
let's create a button.
And when we click that button, let's go ahead and invoke this thing
called increase count.
And let's call it increase.
So now if we click this button, what do we expect to happen?
So notice how we pass this thing called unclick.
What's the value of unclick?
Or what function should we invoke?
Well, we should invoke this dot increase count, which should be this.
We'll see what it is in a second.
And then that should call this dot set state, which
should, in theory, increase count.
So what happens?
Uh-oh!
Cannot read property set state of undefined.
So there's a bug here.
Can anybody spot the bug?
Cannot read property set state of undefined.
It even tells us exactly where that was.
So we're seeing this dot set state, which
I told you is a method that we can use.
But it's saying, we cannot read a property of undefined,
which implies that this is undefined here.
Yeah?
What do you think is going on here?
AUDIENCE: [INAUDIBLE]
JORDAN HAYASHI: Yeah.
So we have to bind that function to this.
So we talked about this and binding this towards the end of last lecture.
And we talked about how this is bound on whatever object it's invoked on.
And so right now, this isn't invoked on the class, right?
It's invoked when you click that button.
And so we're going to have to bind this to the value that we want it to be.
And so towards the end of the lecture, we talked about different ways
to bind this.
Can anybody remember those?
Yeah?
AUDIENCE: Bind method.
JORDAN HAYASHI: Yeah.
There's this thing called bind, which is a method on all functions.
And similar to bind there is call and apply.
And we also talked about a different way of writing functions,
which actually lexically binds this.
Do you guys remember how that was?
Remember, if you use arrow notation, it automatically binds this for you.
And so you can solve this problem in all three different ways.
And so down here, if we wanted to do dot bind,
we could do dot bind to this, which, since we're invoking it
on the render method, which is a method that's invoked on the class,
this is bound correctly.
And so when we increase it, it will increase.
We could also use--
well, call and apply don't really work here.
But we could actually use arrow notation.
So we can say, let's have an arrow notation down here,
which creates a new, anonymous function.
And what does that anonymous function do?
Well, all it does is invoke increase count.
And so since this we wrote as an ES6 arrow notation,
it automatically binds this to be what we want it to be.
Does that makes sense?
There are a couple other places that you could do this.
We could also do it in the constructor method.
You could do this dot increase count equals this dot increase count dot bind
this.
Or lastly, you could also--
and then down here, you'd just have to do this dot increase count.
Or alternatively, you could actually just define this in the constructor.
And so that would be the other way.
So you could say, this dot increase count equals an arrow notation in this.
But let's stick with this way for now.
Cool.
So now we have a button that works, that increases as we expected.
So what if instead of increasing it by 1, we wanted to increase it by 2?
Well, of course, you could just do this.
Let's say we want to do it by sending state twice.
So what do we expect to happen here?
We expect it to set state to be count as this dot state dot count plus 1 is 1.
And then [? it does ?] set count to be 1 plus 1 to be 2, right?
But we see it's only going up by 1.
Why might that be?
Well, set state calls are actually batched and run asynchronously,
which means React is smart enough to know that if this dot set state is
getting called a bunch of times in a row,
rather than immediately doing that, maybe it would be better to just batch
them and do it all in one go.
And like I said, if you pass an object to this dot set state,
it will just merge it into the new state.
And so what is actually happening when you
call this dot set state twice in a row?
Well, they get batched together.
And so it says, OK, now we know we need to merge
into the old state these two objects.
And so it's basically saying, merge the current state-- in this case,
it's count is 0.
And then what are we merging into it?
Well, we want to merge this dot state dot count plus 1.
And then we also want to merge that same thing again.
And so what happens when you merge these three things together?
Well, these two get merged together, and it actually turns into this.
Well, you go left to right, so count gets merged,
gets replaced by this dot state dot count,
which then gets replaced by this dot state dot count plus 1.
And so that is actually just 0 plus 1, which is why we end up getting a 1
here.
Does that make sense?
And so we can prove that it runs asynchronously by logging.
So what do we expect this dot state dot count to be at line 21?
AUDIENCE: [INAUDIBLE]
JORDAN HAYASHI: It actually logs 0, because when you call this dot set
state, all it does is add it to that queue
that we know it's eventually going to execute.
Same with this dot set state.
It gets added to a queue as well.
And so when we get to line 21 here, what has actually executed?
Well, nothing.
And so this dot state dot count still has a value of 0,
and then only after that do those batch set states run.
So what if we actually did care about the previous count before?
Say we wanted to add 1 to the previous count,
but we actually really wanted that state to exist beforehand.
Well, we can pass it what's called an updater function,
and that's a function that takes the previous state
and returns some new state.
In this case, we want it to be the previous state, dot count plus 1.
So now we have two set states, where rather
than just passing an object to emerge, we're saying,
actually run this function.
This function takes the old state and returns
a new object, which is where the count is the previous state's count plus 1.
And so now when it batches it, it says, oh, we actually
need to run this function twice.
And so now when we click, it actually goes up by two.
So any questions on React, props, or state thus far?
Cool.
Let's go ahead and take a quick break.
And then when we come back, we can play with React a little bit more.
Hello, and welcome back.
So before the break, we were talking about React and props and state.
And now with all three, we can actually go ahead and start
building pretty powerful apps.
And so for homework, for the project zero,
you guys have been working on a to do app, which you've
been writing in all vanilla JavaScript.
And today for the rest of the class, we're
going to go ahead and together implement that in all React.
So what are some strategies you may go around doing
your thing in vanilla JavaScript?
Well, say we had to dos created as list items, where within each list item,
we have input, which has a checkbox.
Maybe you're doing the challenge and you want to take care of the deletes
as well.
And then, of course, you're going to have some span
or some way of displaying text.
And so maybe have a couple different functions.
One is to create a to do.
One is to delete a to do.
And what might you do in those functions in order to create those to dos?
Well, first, maybe you'll get the text.
Then what?
Maybe go ahead and using document dot create element,
maybe you want to create a list item.
Then what?
You'll probably have to create the input.
Then probably create a button.
Create the span.
And maybe at the end, you hook those all up together
and append those to the list.
And so how might you take care of delete?
Well, find the to do.
Maybe delete that.
Then what?
Make sure to update the counts.
And maybe we have to do that over here as well.
So you see how we're doing this in a very imperative manner.
Using JavaScript, we tell the browser exactly what we want to do.
Well, we know that our to dos are shaped like this.
So first go ahead and get the text.
Maybe create that [INAUDIBLE],, create the checkbox,
create all these other things.
Append them to each other, and maybe append them to the list.
And so we go ahead, and we created a new to do, but we had to do a lot of steps
in order to get there.
And so what might be an easier way to do this?
Well, in to do one, maybe we wanted to abstract out the creation of the
to do itself.
So maybe in that new create to do function,
we go ahead and make the list item, make the input, make the button,
make the span.
Hook those all up together.
But that's one, little, discrete part of the UI, right?
We're going to start to componentize these things.
Maybe abstract out a function for creating the to do, and then in the new
to do, we can still get the text, update the counts, and append to the list.
But rather than doing all of this work in the new to do function,
maybe we just invoke create to do.
And so we're starting to break out something
that was pretty complicated into now two separate steps, where
each step is relatively simple.
But still in each step, we have to go about all of these steps
in order to get what we want.
So what might be a better way to do this?
Well, rather than going through the steps, where we say, oh, hey,
get me a new element called a list item and input button in a span,
maybe we wanted just to write that all somewhat declaratively ourselves.
And so we can actually do something called innerHTML,
so say we created a list item.
And maybe we want to take advantage of JavaScript's ability
to do in-line string concatenation in order
to create some HTML directly here.
So we could do something like li.innerHTML,
and we can start actually putting this directly in here.
And so this will actually, in a more declarative manner, say,
hey, I want an input, a button in the span,
and just stick this in the innerHTML of that list item.
And so it's starting to look somewhat like something
we've seen before, right?
It's starting to represent more of a React component.
Do you guys see how that is starting to look a lot like what we were
doing before, using React components?
But let's stick with vanilla JavaScript still and take this a step further
and actually store the to dos in memory.
And so what have we been previously using to store to dos?
Well, we've just been adding them to the DOM,
and then using the DOM as a way to remember exactly what our to dos are.
But what if we actually wanted to rather than storing it on the DOM,
actually store that in JavaScript, in some sort of data
structure in our JavaScripted memory?
Well, that might be easier to do stuff like delete on.
But how are we going to get that to the DOM?
Well, we're going to actually have to write a method ourselves.
And so maybe we have to dos stored in memory as an array.
Maybe we have something called a render to do,
which will actually render a single to do.
And by render, I mean turn that to do, an object in memory,
into actual HTML, something that the browser can display.
And so that takes care of rendering a single to do,
but how are we going to render that entire to do list?
Well, maybe we want to clear the list and actually map over the to dos.
So we do to dos dot map.
What are we mapping?
Well, let's actually render each of those to dos.
And for each of the to dos that we rendered,
go ahead and append that to the list.
And so now we went from storing to dos in memory,
creating this concept of rendering, where we turn a single JavaScript
object into an actual thing that the browser can display.
And then we have this concept called render, which
actually renders all of our to dos.
And so we go from what used to be a very imperative way of writing
JavaScript, and going from having a single to do to appending that
to the DOM.
So now we're a more declarative way.
We're declaring that a bunch of to dos may exist.
We're declaring that, hey, here's a way to render a single to do
and writing a way to turn that list into a full rendered page.
And so now when we want to add a to do, rather
than doing a bunch of DOM manipulation, maybe we actually
want to just do something like a new to do and push that to the list.
Well, once you push it to the list, now we have to manually say, hey,
we updated the list.
Let's go ahead and render that to the page.
And so now if we're storing everything in memory,
it becomes a lot easier to remove things.
And so how are we going to remove the to dos?
Well, we have to figure out exactly how to do the to dos,
and this is just an implementation detail.
But we can actually reset to dos to be a filtered list.
So just filter them by excluding that to do that we didn't want to be included.
And then we, again, since we changed everything,
now we're going to have to go and manually kick off a render.
And so now we're writing JavaScript in more of a declarative paradigm, more
like what we saw in React earlier.
But we're still implementing stuff like rendering and rendering a single to do
and kicking off these things manually.
And let's actually see how this looks if we were all to do it in React,
where React actually handles a lot of the data rendering to the screen,
using a library rather than stuff that we have to write manually.
So let's actually do this from scratch.
First let me save this.
So let's go ahead and actually, from scratch, implement our to do list
all in React.
So of course, we're going to have to store stuff in state.
So rather than having app be a function, what might we want to do instead?
Have it be a class.
And just like in the example I was showing earlier,
we have a concept of rendering that app.
React components actually do this automatically
for you in this render method.
And so let's go ahead and implement that rendering method.
And so returning this.
And now we have a blank to do list.
So now we have a class called app.
It's extending React component, which gives us what?
It allows us to have state, and it gives us access
to this thing called this dot set state in order to update the state.
And this render method goes ahead and just renders a blank div
with a blank UL.
Yeah?
AUDIENCE: In the previous version of render,
why was it returning a [INAUDIBLE]?
JORDAN HAYASHI: Oh.
So the question was in my example to do app three,
why was render up here returning false?
So we'll talk about handling events in a little bit.
But basically, browsers actually all have a way to handle events.
And so if you do something like click a Submit button,
it will automatically go ahead and submit a form for you
and refresh the page.
And so a lot of times, when we actually want to handle that all in JavaScript,
we have to have a way to disable the automatic page refresh.
And so there are a couple different ways to do that.
You can do something like event dot stop propagation or event dot--
I forget the exact method name, but it's something
like stop this event from happening.
Prevent default. Event dot prevent default.
And a shorthand for doing both of those is just
returning false out of whatever handler they do.
And so when I do return false from this render, that
means if I ever want to do something, like I
add to do, and hook it up to a button that might automatically submit a form,
I can return false from that instead and automatically
prevent that from happening.
And so this is just some shorthand for rather than having submit buttons
automatically refresh a page, it just blocks that
and lets me handle it all in JavaScript.
Cool.
So back to this example in React.
So we're up to this point where we have a class called app.
Right now, we have no state associated with it, and all we're doing
is rendering this empty list.
And so how might we go about implementing these features
that we have in our to do project?
Well, first, we're going to want to start tracking something
in [? our ?] state, right?
Maybe we want to track the to dos.
And so how do we go ahead and create something called state?
Well, first, we want to invoke the constructor, which
for now takes no arguments, since we're not actually passing any props to app.
First thing we do in the constructor is always
called the super, which is invoking the constructor on React.Component,
which gives us things like this dot set state.
And then now we have the opportunity to initialize our state,
so we can go ahead and do this.state equals whatever.
And so what might we want to store in state?
AUDIENCE: To do list.
JORDAN HAYASHI: Yeah, the to do list.
Is there anything else that we should store?
Nothing I can think of off the top of the head.
But thankfully, if we want to add something later, it's very easy to do.
And so let's just do to dos, and let's store this all on an empty list.
Cool.
So now we have this concept of state.
We now have this concept of to dos, which is stored in our state,
but we're not doing anything with it.
And so let's actually render those to dos to the screen.
So we might want to do it within the unordered list.
Let's have something like this dot state dot to dos.
And again, we wrap things in single curly braces
when we want to execute them as JavaScript.
And so we have this dot state dot to dos, which is an empty array.
But we can't just take for granted that it's always an empty array.
The point of writing declarative code is that we want this to hold true,
no matter what the state is.
And so we just assume that this is full of to dos, and so we can go ahead
and map over that and render each to do.
So for each to do, let's actually create a to do.
All right, so I'm mapping out the to dos, and for each to do,
I'm creating this tag called uppercase to do.
So who remembers what uppercase tags mean?
AUDIENCE: It's a React component.
JORDAN HAYASHI: Yeah, it's a React component.
And we now have to describe something called a React component called capital
to do.
And so let's go ahead and do that.
And so just like the examples that I showed you earlier,
where we abstracted out the concept of creating a to do,
we can do that in React as well.
So let's have this thing called a to do.
And what it does is it takes some props.
We can call this variable whatever we want,
but the React convention is to call it props.
And what are we going to return?
Well, let's just return an unordered list, or a list item.
What might we have in that list item?
Well, we had an input of type checkbox.
We had a button that allowed us to delete.
And last but not least, we had some text.
And what was in that text?
Well, probably just props, dots--
we can call it the text for the to do.
Cool.
So now we declaratively just said, hey, every time we want a to do,
this is what it looks like.
It's a list item, and inside it, we have an input.
It's going to be a checkbox.
We're going to have a button called delete.
It doesn't actually do anything for now.
And we also have a span, and what's that value of the span?
Well, just look at my props and grab the text.
OK, so now what do we have to do?
Maybe we should add a way to add to dos.
So let's create a method called add to do.
And what should we do first?
Maybe we should get some text.
So there are many different ways to do this.
Let's just for now prompt.
And then what do we want to do with that?
We have text.
What should we actually do with it?
AUDIENCE: Add it to the to do list.
JORDAN HAYASHI: Yeah, we should add it to our to do list.
And how are we going to do that?
We can just do this dot state equals something, right?
No.
There's only one way to update state, right?
We should do this dot set state.
And what are we doing?
Well, we have the to do equal this dot state dot to dos.
And then additional thing.
And so the way that we've added to an array
thus far is by doing this sum array dot push.
What that does is it actually mutates the array.
And so the way that React knows that it should update
is it sees if the values that are passed to it are different.
And as we learned a couple lectures ago, all objects
are actually stored by reference.
And so when we go ahead and mutate an object,
the reference doesn't actually change.
And so the React paradigm is rather than mutating these props,
we should actually create new ones.
And so a quick way to create a new array is
by using this dot dot dot notation, which
means given an array, if you dot dot dot array,
it just pulls out all of those values of the array.
And so when we do something like brackets dot dot dot some array,
it pulls out all the values of that array and puts it into a new array.
And so this is a quick way of cloning an array.
And so now the array reference is changed, but the values in there
are all the same.
And so now we've cloned the array, and now we should add a new to do.
And so let's call our to dos objects that have a text field,
and that can be the text.
So there's a small bug in our program now.
Well, one, we don't know how to add a list.
Add to that.
So let's go ahead and create a button that can add a to do.
So now you have a button, but it's not actually
doing anything when we click it.
So first we need to set up an event handler,
so when that button is clicked, what should it do?
Well, it should do this dot add to do.
So what is wrong with this code?
Why isn't it working?
Yeah, this is not bound to what it should be.
And so how are we going to fix that?
Well, the easiest way is to just declare an arrow
function in line here, which will lexically bind what we want it to do.
And so now we have another bug, so we declared
to do to be a list item with an input, a button, and a span.
And we see the input in the button, but we don't see any spans.
So does anybody spot exactly why that's happening?
So what text are we populating that span with?
Props dot text.
And so what does the object called props--
what values are in there?
They're key value pairs that are mapped to what are passed in here.
Are we passing a key called text into to do?
No, we're not.
We're only passing something called to do, right?
To do may have a value called text, but in order
to actually access that, what we would have to do is to do props.todo.text.
And that will allow us to pull up the correct field.
So now we have a way to add to dos.
Great.
That doesn't make much of a to do app.
We should be able to check and uncheck, which we can.
But we're not really handling that in state.
We have no way of telling whether these to dos are checked or not,
and we also have no way to delete to dos.
And so we need some sort of way to recognize which to do is which.
What are some strategies to go about doing that?
Can anybody think of one?
AUDIENCE: [INAUDIBLE]
JORDAN HAYASHI: Yeah, we should give each one an ID.
That way, if we can guarantee that those IDs are unique,
then we'll have a unique way of recognizing each to do.
And so let's go ahead and do that real quick.
So a very easy way to do that would be to do something like this--
have some value called ID declared outside, initialized to 0.
And every time you create a new one, you just increment that.
And so now every single time we add a to do, it has an ID field.
And we're guaranteed that it's unique, since it's
a counter outside the state of our app.
Does that makes sense?
So how does that help us?
So now we have a way of recognizing which to do is which.
And so say we wanted to get rid of one, it's now pretty easy to do that, right?
So if we want to now remove to do, that should now do what?
Does it make sense to have a remove to do with no arguments?
Not really, right?
Because we need to know exactly which to do we want to delete.
It makes sense that we want to add a to do with no arguments,
because there's no particular to do that we want to add.
We create that text later.
But when we want to remove a to do, we need
to know exactly which to do to remove.
And so now we should have remove to do actually taking argument.
And so what argument should it take?
Well, we created some sort of unique identifier field,
so we can just take the ID.
And so now how are we going to remove the to do?
Well, we could do this.setState, which is the only way to update the state.
And the to dos are what?
They can take the old state's to dos and just filter them, where for each
to do, what do we want to keep?
Well, as long as the to do dot ID is not equal to the ID that we pass in,
those are the to dos that we want to take.
Great.
But the Delete button is not working.
Why not?
Well, our component called to do is not doing anything
when you click on the button.
So how might we handle that?
Well, that's where props come in.
Since we can pass any JavaScript value as props,
what's to stop us from just passing a function down?
And so when we map over the to dos like this,
we can actually also pass a function down.
So we could pass something called onDelete and just pass a function.
And what would that function do?
Well, it's going to call this.delete removeTodo.
And what are we going to pass in when we invoke that?
Well, this todo.id.
Does that make sense?
So we're mapping over to dos, and for each to do in that array,
we're going to invoke that to do function, that component.
And what are we passing as props?
We're passing it this thing called onDelete
which is a function that invokes remove to do with that to do's ID.
So for each to do that we create, we're passing
a unique function that removes that particular to dos
from our global state.
And of course, we're also passing down the to dos,
so it knows exactly which text to render.
And so how do we get that to fire when we click the delete button?
Well, that function's just a prop, right?
So when we click that button, what should we do?
Well, we should invoke props dot on delete.
And so now when we add things, if we click that button,
the correct one is deleted.
Again, how does it know that that first one is the one that should be deleted?
Well, it's because each to do that gets rendered,
so when we map over the to dos in our state, we pass a unique on delete
handler down.
It's a function that gets bound to that particular to do's ID field.
And so when we click that particular to do's delete button,
it invokes remove to do with that ID, and so it knows
to filter based on that particular ID.
Does that make sense to people?
Great.
So we've handled the two big parts--
well, the add and the delete part of the assignment.
And so what are we missing?
We're missing some way of tracking how many to dos we have total
and how many to dos that we still have to complete-- or in other words,
to dos that are unchecked.
And so now we have a choice-- how are we going to handle this?
Well, if we were back in Vanilla JavaScript world,
a way to do that would just be to keep track
of however many unchecked there are, keep track of however many total
there are.
And just mess with those values every single time we add, delete, or check
or uncheck a to do.
But in React land, that seems a little imperative for our like,
and so there might be a more declarative way to do this.
But in order to do that, we also need to track every single to do,
whether it's checked or not.
And so currently our to dos are an ID field and a text field.
But maybe it would be better to also add a field of whether it's checked or not.
And so now when we add to dos, we add an object with three keys--
an ID which is guaranteed to be unique, because we're incrementing
this ID counter, which lives outside of our app; the texts that we prompt for;
and lastly, a value called checked, which keeps track of whether that to do
is checked or not.
And we should just initialize it with false,
because there's no point in creating a to do.
That's already done.
Cool.
And so now we're still missing one thing.
So when we create to dos, we just create an empty checkbox.
And so no matter what, it's going to be unchecked.
And so we should set that check field to equal whether that particular to do
is checked or not.
And so how might we do that?
Well, with props.todo.checked.
And so now that keeps track of whether a to do is checked or not.
But the problem is we're not actually updating our app state every time
a to do is checked or not.
And so we're going to have to actually handle every single time
an input is clicked.
Every single time it changes, we need to update our app state accordingly,
because if you look here, I'm clicking but nothing is happening.
Why is nothing happening?
Well, we're initializing our to dos to be checked if false.
We're saying, for each to do, make sure that checkbox, whether it's checked
or not, is whether that to do--
its check value is true or false.
But we have no way to change that from not false,
and so no matter how many times I click that,
it's not going to change the value of props.todo.checked.
And so we're going to actually have to write some logic in order
to handle that.
And so now let's create a new method, called toggle to do.
We're obviously going to need to take an argument here, because we
need to know which to do to toggle.
And so what are we going to do here--
so again, we're going to do this.setState and we can to dos.
It's this.state.todos.map.
So if you remember back a few lectures ago, when we talked about filter, map,
and reduce, we talked about how map applies a function to each
of the values in an array and will return
a new array with those values swapped out
with whatever this function returns.
And so how might we use that map function to handle the toggling of a
to do?
Well, first, which to do do we actually care about?
We only care about the to do with an ID that
matches the ID that were passed, right?
So we can immediately off the bat say, if to do
dot ID is not equal to the ID that were passed, what should we do?
AUDIENCE: [INAUDIBLE]
JORDAN HAYASHI: Yeah, we shouldn't do anything, right?
We should just return that to do.
OK, great.
We have one condition, but what happens with the to do that we want replaced?
We should flip its checked value, right?
And so we're going to want to return a new object,
and what should those objects' field be?
Well, we can say, ID is to do dot ID.
We can do text is to do dot text.
And what do we want the checked value to be?
AUDIENCE: [INAUDIBLE]
JORDAN HAYASHI: Yeah, the opposite of what it was before.
And now it looks like we should have something that works.
The problem is it doesn't.
It still doesn't change anything when we click this value.
Anybody have any ideas why not?
It looks like our toggle to do function should work.
We're setting state, we're updating the to dos,
we're mapping over this with this function,
where if the to do's ID doesn't match, we don't change it.
But if it does, we flip the to check value.
But when we click over here, nothing actually happens.
Why might that be?
Yeah?
AUDIENCE: [INAUDIBLE]
JORDAN HAYASHI: Yeah.
Exactly.
We defined this function, but we're not actually calling it anywhere.
And so just like we have this onDelete that passes a new onDelete
function to every single to do, we should also
have this thing called onCheck or onToggle that
passes the unique function to each to do that we
should invoke when we toggle it.
And so let's have an arrow function here so we don't
have to worry about the this binding.
And when on toggle's invoked, we should do this.toggleTodo with the todos.id.
And so now since we're passing a new prop here,
we should probably invoke that prop at some point.
And so where are we going to do it?
Well, we can do it in the input.
We can do something like onChange = props.onToggle.
And how do I know that this on change attribute exists?
Well, you can read the docs and it'll be there.
Or you can wait till the next lecture, when
we talk about event handling in React.
And so now we can create a to do.
And when we click it, look at that-- it works.
Cool.
So now we're tracking every single to do, whether it's checked or not.
But that wasn't really the goal, right?
The underlying goal was to keep track of how many to dos there were,
and how many unchecked to dos there are.
And so how might we do that?
Well, first let's create some divs.
This div says to do count.
And then we're going to have some JavaScript in line there,
and then maybe a div for unchecked to do count.
And again, some JavaScript.
Cool.
And so what is a quick and easy way to calculate how many to dos we have?
We're tracking all of our to dos in memory.
What are we using to track them?
Yeah?
AUDIENCE: [INAUDIBLE]
JORDAN HAYASHI: Yeah.
It's just an array that has a length attribute,
so we can do this dot state dot to dos, which grabs that list,
and just do dot length.
And now we have a 0.
And if we add a to do, it goes ahead and increases.
Cool.
And so how are we going to keep track of the unchecked to dos?
Well, we know we're tracking every single to do and whether it's checked
or not.
And so one strategy might be to get all of the to dos,
remove all of the ones that are checked, and then count the number remaining.
So what functions might we use to implement that algorithm?
Yeah, we can use the filter function.
So we can do this dot state dot to dos dot filter.
And what are we going to filter by?
Well, for each to do, return if it's not checked.
And then we're left with a new array, and we can just grab the length.
And so if we do a test, now we have it unchecked.
What happens when we check it?
Well, that's going to get filtered out here, and what's left is an empty list.
And you grab the length of that, and we have 0.
What happens when we delete it?
Well, we don't actually have to update any logic,
because everything is handled completely declaratively.
Is there anything here that says, every time
we change something, make sure to go and change this count that we're keeping?
Not really, right?
We just assume that we have some to dos and some data that's coming down,
and we just run calculations based on that data.
And so we're just declaring what we want, based
on any data that's passed into us.
And so React, in that way, is very declarative.
And so this is great.
If we want to add any new features, we don't really have to worry about, oh,
what is every single possible method that we
need to update this new feature with.
Whereas if we were doing this in more Vanilla JS
and more an imperative nature, we would have
to make sure, oh, if we want to also keep track of the count of checks
to dos, we're going to have to check every single method where
that number might be affected and go ahead and update it there.
And so keeping track of all that in your mind
might create bugs that you might not otherwise
if the paradigm were more simple.
And so this is a much more simple way of saying, hey, given some app state,
go ahead and render an app based on that state.
Any questions?
Yeah?
AUDIENCE: [INAUDIBLE]
JORDAN HAYASHI: Can you repeat your question?
AUDIENCE: [INAUDIBLE]
JORDAN HAYASHI: So the question was if we,
rather than replacing the old state.todos over here with a new array,
would it still work, if we were to mutate the array?
And the answer to that is, it depends.
It depends on the React component that you're using,
and it depends on some other methods that you
could write that we'll talk about in future lectures.
But the fact that it depends is a bad thing,
because then you don't really know--
it depends on what else you've written, whether it will work or not.
But if you do it like this, where it's a completely new array,
it will always work.
And we'll talk about this in future lectures,
but the React paradigm is always to do things immutably,
which means if you ever change something, replace it
with something completely new.
And that-- be a reference to that.
That way, if you're ever comparing values,
you don't have any bugs that can appear there if you've mutated a value.
So technically it's changed, but the reference to that value
has not changed.
Does that make sense?
Cool.
Any other questions about React, props, state, or anything
that we've seen today?
All right.
So we talked about to do app.JS and using React on the web.
But why limit React just to the web?
So there exists this thing called React Native, which
is a framework that relies on React Core and the core algorithms implemented
by the React library.
But it's actually a framework that allows you to do much, much more.
It allows us to build mobile apps using only JavaScript.
And so when Facebook released this framework called React Native,
they released it with the tagline, "learn once, write anywhere."
So you only have to learn JavaScript once.
You only have to learn React once.
But you can actually write it, and it'll run anywhere.
And this supports both iOS and Android.
And so I'll leave you there for this lecture, and next lecture,
we'll look at this thing called React Native
and how to run JavaScript for mobile apps.