[MUSIC PLAYING]
SPEAKER 1: Hello and
welcome for Lecture 5.
This week we'll be talking about
user input, which we discussed
a bit last week, and debugging.
So in the previous lecture, we
discussed a few different concepts.
We talked about scrolling views, which
are the views where you can scroll.
The caveat to that being that all of its
children render before the whole view
renders.
We talked about a couple virtualized
lists, flat list and section list.
Those are the couple lists where they're
much more performant because they'll
only render what's in view.
The difference being
that section lists allows
you to separate your data into
different separate sections
and have a section header
to go along with those.
We then started to
talk about user input.
We talked about the difference between
controlled and uncontrolled components.
Controlled components
being those components
that track state and the source
of truth for the input's values
are on the component state itself.
Whereas uncontrolled components are
those where the Dom, or in the case
of the browser, the browser itself
keeps track of those input's values.
We then talked about text
input for a little bit,
which was the component
used to accept user input.
And first, we'll talk
about user input today.
And so we talked
briefly about controlled
versus uncontrolled components.
And how for React native, you
need to use controlled components.
React recommends always
using controlled components
even when using React web as well.
And so we looked at how user inputs
take a couple of different props.
One value which dictates what the value,
or what displays inside the text box,
is.
And then unchanged text, which
is the callback that is invoked
every time you change that value.
And so the docs are linked
in the lecture slides.
And so let's take a look at the example
that we were looking at last week.
So last week we were
writing this application
where we have a section list here.
And then we are starting to add a screen
where we can add contacts to that list.
And so, where we left off last week,
we could type into the name here.
We could type into the phone here.
But nothing actually
happens with those values.
And when we click
submit, nothing happens.
Let's build out the rest
of that app this week.
So in add contact form, when we left off
last week, we had a few things written.
So we kept track of the name
and the phone number and state.
Let's actually to get
rid of that line here.
So we kept track of
name and phone and state
since we're using controlled components.
The component itself has to
track the value of those texts.
We wrote two separate handlers.
One called handle name
change, which takes a name.
Which is fired when you change
the text and put down here.
And then it just sets the state
so that the name, the key name,
is equal to whatever value is passed in.
And so that, when passed a string, will
just update a state value for name.
We have the same function
down here but for phone.
And so when you pass in a
new phone number down here,
it will just set the state such that the
new phone is equal to whatever string
you pass in.
And then the render function, we
just define those two text inputs.
So one has a value of
this dot state dot name.
And so every time we change
the this dot state dot name,
the value's then reflected
in this text input.
We set its unchanged text prop
to equal that handle name change
function that we defined above.
And then just as a
placeholder, we wrote name.
So that when the field
is blank, the user
just knows what they're
supposed to type in there.
And then we have the same text
input down here for phone.
With the one difference
being the keyboard type.
And so we don't really want the
users to be able to type letters
into the text input.
And so we said what kind
of keyboard should pop up.
Only that numeric one.
And so, as we see in our app, when
we click on the text input here,
we only see the numbers.
And so now we have a page that is
actually handling multiple inputs.
And so the way we handle that in
web is we have a form component.
And so that form component in
HTML takes the on submit handler
and when you submit the
form, that gets invoked.
Unfortunately that does
not exist in React native.
But since we're using
controlled components,
we actually maintain an object
with all of the form data.
So, again, this form
component does not exist.
But the analogy is that, for whatever
component that we're writing,
all of the information that we
need is tracked in the state.
And so we're actually maintaining
an object with all of that,
all those input's values.
And so what we can actually do
is we can define a function that
handles the data to submit.
And so that would be the analogy
to the onsubmit handler in web.
And so let's go ahead and
do that in our example.
And so here when we click
submit, nothing actually happens.
But what do we want to happen here?
Well, when you click submit,
ideally this form gets submitted
and we add a contact.
And so here, we already
have a button called submit,
but we haven't said what it
should do when we press it.
And so let's define an on press.
And so on press is going to invoke
this function called handle submit,
which we have not yet defined.
And let's go ahead
and define it up here.
So, as you recall, when you press
a button the on press handler
gets invoked with no arguments.
And so we're going to
actually have to decide
what to do here with no arguments.
And so we should go ahead and do
this dot props because since this
is just generic add contact form,
we're not defining the logic
on adding the contact here.
We're just going to
define the form here.
And so we're going to
assume that a prop called,
let's just call it on submit exists.
And we're going to pass in
an object with the state
fields that are necessary.
And so we could do something like
name is this dot state dot name.
And phone is this dot state dot phone.
Or the shorthand for here, since
we're using every single key value
pair of this dot state,
we can actually just do
this dot dot dot, this dot state.
Which means, take all of the key
value pairs of this dot state,
and create a new object
with those key value pairs.
Or simply, we could just
pass this dot state.
And so we're going to invoke this dot
props to on submit with this dot state.
And so now we have to define, what
are we actually doing on submit.
So let's take a look at AppJS.
So here is a lot of stuff
that we wrote last week.
But we have not actually written
the way to add a contact.
And so let's go ahead
and implement that here.
So this should take an argument.
So we need to know exactly
what conduct we want to add.
So it takes a new contact,
and what are we going to do?
Well, we should take the previous
contacts and append to that.
And since we rely on the
value in the previous state,
we should define a function
that takes the previous state
and returns a new state, where the
new contacts are the old contacts.
And then the new contact.
And so, again, that dot dot
dot notation with arrays
means take all of those array values
and stick them in this new array.
And then last, add new contact.
So now this function
should take a new contact
and set the state such
that the contacts are
equal to the old contacts with a
new contact appended at the end.
Lastly, we need to pass that handler
down to the add contact form here.
So we call it on submit.
And what should it do on submit?
Well it should invoke
this dot add contact.
Which will invoke that function
that we defined up there.
So let's go ahead and test that.
So now we can go ahead.
Actually let's first just have only
one to begin with so it's easy to see.
Let's go ahead and add a contact.
Let's call him my name.
And let's put some
random phone number in.
So what happened?
I click submit, but
nothing actually happened.
Does anybody see what the bug is here?
So first, how are we
determining whether or not
we should display that add contact form?
Well here it says, if the state
says, is telling me to show the form,
then I should show the form.
Where do we change that?
Well we have a function
that says show the form,
but there's nowhere in any logic do we
say, oh now it's time to hide the form.
So where might we want to do that?
Anyone?
In the add contacts?
Yeah, In the add contact function.
So when we add a new
contact, we no longer
really need to show that form, right?
And so we can say, update the
contacts to the new contacts.
And also say, we don't need
to show the form anymore.
And so now when we add a
contact, the form hides.
And that contact gets
added to our application.
Cool.
Any questions about that?
We can ignore that error for now.
Cool, so is that a real phone
number, one two three four?
It's not.
So we should add some way to check
whether the input is valid or not.
And so next we'll talk
about validating input.
So one way to go ahead
and validate input
is to conditionally set the
state based on input value.
And so one bug that
we actually have here,
is even though for the phone
number only numbers are showing up,
one, I can type dots.
That's probably not ideal.
And then, things break
if I don't define a name.
So that is not ideal.
And furthermore, if somebody
plugs in a physical keyboard,
they can also type things
that are not numbers.
And that is also probably not ideal.
And so let's figure out some
sort of way to say, hey,
if this phone number is not a real
phone number, we should not accept it.
And so one way to do that
is to conditionally set
the state based on the input value.
So let's go back into
that form and do that.
And so where might we want to check
the value of that phone number
before we update the state?
So on line 33 here, we define
the handle phone change,
which is the function that gets invoked
every single time that input changes.
In what we're doing is we're
immediately taking that string
and setting the phone in
the state to be whatever
arbitrary string is passed to us.
But we don't have to do that.
We can actually add some
logic here that says, hey,
we should only allow people to
set phone numbers to something
that resembles a phone number.
And so let's go ahead and do that.
So we can say if phone, and then maybe
do something there, then set the state.
Otherwise, just don't do anything.
And so what might we want
to check on the phone?
We should check if it's a number.
And so how do we check
if a string is a number?
There are actually many different ways
and I'll show you one possible way.
So this plus notation, if
you do plus some string,
it will try to cast that to a number.
And so let's, I can show you real quick.
So say we have a string
that's one, two, three.
If I just do +str, we get
one, two, three as a number.
But what if I do plus
one, two, three, a.
Not a number.
Plus empty string is the case
where it will return zero.
But anything else that's not a
number, will return not a number.
And so we can use this
new operator to check
if our phone number is indeed a number.
Let's go ahead and say if
the phone number is indeed
a number, so is greater
than or equal to zero,
then we can go ahead and set the state.
And so now here, if we start
to type, I'm pressing letters
and nothing's happening.
That's because any single
time that I type a letter,
it's going to invoke this function.
It's going to do if plus
some letter, or not a number,
is greater than or equal to zero.
Not a number is never going to
be greater than or equal to 0.
And so that's never actually
going to invoke down here.
There's still a bug where if I
do one, actually there is no bug.
Right.
So I was thinking that if we typed
empty string here, this would be 0.
But that still evaluates to true.
And so even though phone is an empty
string, plus empty string equals 0
is indeed equal to 0.
And so it will indeed set the
phone number to empty string.
So that's one way to
validate the phone number.
And so now we are ensuring that
the phone is some sort of number.
We can go a little bit further,
because there's nothing
stopping me from inputting a lot
of numbers as my phone number.
So let's just assume that
all phone numbers should
be 10 digits long, until we can stop
the user from putting a number that's
greater than 10 digits long.
How might we do that?
Well, we can just do
if phone, dot length.
And since it's a string, we can
just check the length of it.
As long as it's less than or equal
to 10, we can go ahead and update it.
And so now if we do one, two, three,
four, five, six, seven, eight, nine,
ten, if I try to press additional
numbers, it doesn't update.
Why?
Because when I try to set phone to
a string of length larger than 10,
this does not evaluate to true.
And so the state does not get updated.
So there's still problem here.
What happens if I just click submit?
Well, it errors because there's no name.
And so we should probably also
check that the name exists.
And so we should also go ahead
and validate the entire form
before submitting.
And so what else should we do here?
Well, when we submit we should
make sure that both fields exist.
And so we can say if the
phone number is valid,
and so let's just copy and paste this.
So now phone dot length
should be equal to 10.
And it should be number.
Additionally, we want
that name to exist.
And so let's just arbitrarily
call this dot state dot name.
Should have a length
greater than or equal to 3.
And so now are saying if this dot
state dot phone is greater than 0,
when you cast two number, if the
length is exactly equal to 10,
and you have a name of length at least
10, then go ahead and submit the form.
Otherwise don't do anything.
And so now when we try to add a contact
with invalid fields, nothing happens.
But that's not great UI, right?
I should be able to know that I
shouldn't be able to submit this form.
And so let's go a step further,
and actually every single time we
change the name or
the phone number here,
we can change this
button to appear like it
should be clickable or not clickable.
And so there's an
additional thing that you
can do with button, an additional
prop that you can pass.
We can pass a prop called disabled.
And if we pass disabled true, then
the button just looks unclickable.
And it is unclickable.
And so how might we use this to make
the user experience of our form better?
Well, we can actually continuously
check, hey, if the form's valid,
show the clickable button.
And if the form is invalid, then say,
hey, you can't click this button.
And so where might we
want to do that logic?
Well, we can actually validate the
form after we change any inputs value.
There's a couple of
places we can do that.
One in this dot set state.
And so we've been using
this dot set state,
and we've been passing
it one of two things.
We pass it an object, if we want to just
merge that object to the current state.
Or we've passed it some sort
of update or function, which
is a function that takes the previous
state and modifies or returns an object
modifying that previous state.
Well it turns out, you can actually
also pass a second argument
to this dot set state.
And that second argument
gets invoked as a callback.
So after the state is done updating,
it then invokes this callback.
And so let's go ahead and use
that to validate our form.
So one, rather than just hard
coding disabled true here,
what might we want to do?
Well, we can store in our state
whether or not this form is valid.
So let's just call this is
valid form, or is form valid.
And we know that when the form
is first created, that it's not.
And so we can just initialize
this value to be false.
And so down here in the button,
we can say whether or not
it's disabled depends on the value
of this dot state dot is form valid.
So this will always start as an
invalid form and so we can see, oops.
It should be disabled when
the form is not valid.
And so we can see that when the form
is first created, since is form valid
is false, we can't submit the form.
That button is disabled.
And now we can add
some logic to say, hey,
every single time we check the
input, the form may now be valid.
How might we want to do that?
We're currently checking whether
or not the form is valid right
before we submit the form.
But there's nothing stopping us
from just abstracting that out
to a new function.
So let's call this validate form.
And it doesn't need any arguments.
Just because we're going to call it,
and it will check the current state.
And so here we can say, well,
if these things are true,
then maybe return true.
Else return false.
Because it's not a valid form.
And so although this isn't
perfect, we can still
have dots in our phone number.
It's close enough.
And so now, when we invoke
validate form, it's going to check.
Hey, is the phone as a
number greater than zero?
And is it of length 10?
So we'll just call that a phone number,
even though it's not 100% rigid.
And then, did they put
something as their name?
It has to be at least three characters.
And if that's true, then it will
say, hey, it's a valid form.
Otherwise, no it's not a valid form.
And so where should we
invoke this function?
Well, after a value changes.
And so right now the only two
places that the values are updated,
are in this handle name change function
and this handle phone change function.
And so we can pass now as a second
argument to this dot set state,
this dot validate form.
And as a second argument to handle
phone change, the set state here,
we can also pass this dot validate form.
And now this validate
form function is going
to get called after either
of those functions are fired.
As we've currently written it, validate
form does not actually do anything.
It just returns true or false.
And so what should we do instead?
Well, this should tell us
whether the form is valid.
And so if the form is valid,
let's actually set state here too.
Now in validate form, rather than
just returning true or false,
it will actually update the state
such that the is form valid field
gets updated to true or false.
So now let's see how our
application functions.
So when we first start this form,
the submit button does not work.
And let's add a name of two letters.
And a phone number of 10.
And the validation still works.
If we try to type more
here, it doesn't let us.
And now, let's type a third letter.
And all of a sudden that
submit button works.
Why?
Well, because when we pass another
argument to set state here,
that gets invoked
after the state is set.
And so after it updates the name
value, now the name value in state
is whatever it was when
we typed in the input.
And then it fires off this function.
And this function says, hey,
if the phone number is valid
and the name is at least
three characters, go ahead
and say the form is valid.
And what it's listening to that
is form valid part of the state,
well it's the button down here.
And so when that is
updated, the button then
flips from disabled to not disabled.
And when we delete this and
when it becomes invalid again,
that submit button reflects
the in-validness of the form.
Any questions so far?
So how are other ways
that we can do this?
Well, we learned a few weeks ago
about the component lifecycle.
And how there are certain functions
that are called every single time
a React component does something.
And in this case, we
can actually use that,
the hook that's invoked every single
time the form or the component updates
to go ahead and fire this as well.
And so if we wanted to, rather than
invoking this dot validate form
and handle phone change
and handle name change,
we could also do that in
the component did update.
And component did update takes
a couple of different arguments.
One is prevProps and one is prevState.
And what can we do here?
Well, we can just call
this dot validate form.
And so something interesting
is going to happen here.
Hm.
We got a big error screen.
Maximum update depth exceeded.
This can happen when
the component repeatedly
calls set state inside one of
these component lifecycle hooks.
And so React is saying, hey, rather
than just infinitely looping,
we just threw an error.
And so what is happening here?
Let's take a look.
So when we go ahead and type
into type and input here,
text input, something happens.
One of these two functions
is going to be invoked.
What happens when it's invoked?
Well, the whole component updates.
And when the component updates,
it calls this dot validate form.
What does this dot validate form do?
Well, it checks some things
and then calls set state.
And then when set state
happens, the component updates.
And what happens when
the component updates?
Well, it validates the form.
And then what happens
when you validate form?
Well, the component updates.
And so we entered a cycle
where it just infinite loops.
So how can we fix that?
Well component did update
knows about the previous props
and the previous states.
It also knows about the current
props and the current state.
And so we can go ahead
and check those values.
And say, if this dot state dot
name is different than what
the previous state dot
name was, or this dot
state dot phone is different than it
used to be, then validate the form.
Otherwise don't do anything.
And so now when we do
stuff like this, it works.
And when we type a tentative phone
number, then the form becomes valid.
What happens when it's invalid?
Well, it works as expected.
And then when it becomes valid
again, then all of a sudden
that submit button appears again.
And then everything
else works as expected.
And so the other place
that we can validate
a form is just in that component
did update lifecycle hook.
And so what's the difference?
Well, not much.
One difference is that
when we add new functions,
we also need to remember
that in the set state,
we need to pass that
validate form field.
But on the flip side, every
time we add a new input,
we also need to make
sure that we're listening
at the correct times in
component did update.
And so the performance
of the two is equal.
And so, whether you choose one or the
other is more personal preference.
The way I would write it is I would
prefer to put it in the component
did update, but it's really up to you.
This is almost complete
personal preference.
Any questions this far?
Yeah?
SPEAKER 2: So when you put
the is for valid function
directly in the disable
attribute, does it know
to-- does it not know to update that?
SPEAKER 1: So the question was, when
you put the is form valid value here,
does it know to update that?
And so, yes.
So this is not the is
form valid function.
It's just the state key
called is form valid.
And the is form valid key is updated
when the validate form is called.
And so React knows every single
time the state is updated
that the render might change.
So it's outputted by
render might change.
And so every single time
we call this dot set state,
the component is then re-rendered.
And the correct value of is form valid
will be placed as this disabled prop
to the button.
SPEAKER 2: Do you always
have to use the state
to determine whether
disable is true or not?
Can you use a function instead?
SPEAKER 1: So the
question was, do we always
have to use the state field
to determine whether or not
this form is disabled or not?
Could we just use an
inline function instead?
So the answer is no.
So we could definitely-- we can
use a function here instead.
And so say we actually validate form.
Say we implemented it
how we did at first.
So let's call this
validate form two, where
rather than setting state to
update that is form valid field,
we just return true or return false.
And then we can--
and so now down here we can
just invoke that function.
This should work.
So now if we oops- This
dot is form valid two.
Validate form two.
So if we call this validate form
two, so this should, in theory, work.
I forgot to flip the Boolean, but
you see that the Boolean does change.
And so what is that what is the
difference between these two?
The difference here is that
this function is actually being
computed as the render is happening.
And so say it took a lot of work
in order to validate this form.
Say it took a whole second.
What's happening to the
user in that second?
Well nothing's showing up because
React doesn't yet know what to render.
And so the render here
will take a full second.
And so the user won't see
anything until a second later.
And so that's considered
bad user experience.
Whereas, when we do the validate
form in the update cycle,
it's already rendered this.
So the user's already seeing this.
And then when the component's updating,
that's when it does the computing.
And so the user sees what
the user needs to see.
And then the expensive computation
is done after the user has already
seen the form.
And so there is, on
the user side, he gets
to see the form rendered
before this is calculated.
And so if you do it inline here, it's
actually going to slow down the render.
Whereas if you do it in
like component did update,
it actually happens after the render.
And so the user gets to see the form
before this computation happening.
And so it would be better to
just store that value in state.
That way you can recompute
it at a convenient time,
rather than having to do a
potentially expensive computation
during the render.
Does that make sense?
Cool.
So let's revert this to this
dot state dot is valid form.
And we're back to where we were.
Great, so this works really
well for short forms.
But what happens if, say we
wanted to center the form.
So now, in my opinion, the
form looks slightly better.
But when we're bringing
up the keyboard, it's
starting to get dangerously
close to the input here.
And so what happens if this
form were slightly longer?
Say now we had six things to fill out.
Now when we click phone, uh oh we have
something that's considered probably
some bad user experience.
That is, the input's getting
covered up by the keyboard itself.
And so you may start to run
into problems like these
when you're working on your projects.
And so how might we go
about in fixing that?
So it turns out, there's
this thing called
a keyboard avoiding view,
which is a native component
to handle avoiding
that virtual keyboard.
It's good for simple or short
forms, but it doesn't really
work well for very complex things.
And what happens here, and
the reason that's not good,
is because the view moves independent
of any of its child text inputs.
Let's take a look at
usage of this component.
So right now we have a view
that surrounds these inputs.
And let's actually import this thing
called a keyboard avoiding view
instead.
So now, rather than just using a view,
we can use that keyboard avoiding view.
And same up here.
So now the keyboard avoiding view
that actually doesn't look like it's
doing much.
That's because we need to tell it
what to do when the keyboard arrives.
And so we can pass this
prop called behavior.
Which is saying, hey, what should I
adjust when that keyboard appears?
It can be one of three things.
It can be padding, which means
when the keyboard appears,
go ahead and add some padding
to the bottom of the view
so all of the content moves up.
It can be height, so that rather
than being a full height view,
it will actually change
the height of that view.
Or third, it could be position where
it actually repositions the view.
Which one is best depends
a lot on your use case.
And so, the docs say, hey, just
try whichever one is best in it.
You'll see.
And so here, let's go
ahead and use padding.
And so now we specified some behavior
for that keyboard avoiding view.
And so when we click, it goes
ahead and moves that view out
of the way of the keyboard.
And when we're done, it goes
ahead and moves it back.
And how does this happen?
Well, this view just
gets some added padding.
So this is a relatively new component
and it is still getting better.
And so hopefully, this will be able
to handle larger forms in the future.
But for now, it works perfectly
well for small forms that
will fit in the space outside the view.
So any questions on user input at all?
Cool.
Let's go ahead and take a short break.
And then after the break, we'll go ahead
and look get some debugging techniques.
Hello and welcome back.
So before the break, we were
talking about a few different forms
and how we handle user
input in the forms.
And there was a question in
Slack asking a great question.
And so in this form right here,
we have two different inputs.
We have the name in the phone.
And we also have two different handlers.
We have the handle name change
and handle phone change.
This doesn't scale super well.
Imagine you have a form
with 100 different inputs.
It would not really be
a great component if it
were filled with a hundreds different
handlers for all those inputs.
And so let's go ahead and take a look
at a pattern for how we can go ahead
and update all of
those handlers, but not
have to write separate handlers
for each of the separate fields.
So if you notice, both of these
handles look very similar.
We have some string that gets passed
in, and then we set the state such
that the key is equal to that string.
And the phone does
some validation before,
but it basically does the same thing.
It takes a string and sets a
particular key equal to that string.
And so we can go ahead
and abstract that out
into a more generic updating function.
So let's just call it handle update.
And that's going to take a
couple different arguments.
Let's actually have it take
a key and return a function.
It's going to return a function
that says, take some sort of value,
and then call this dot set state.
And then the object here,
we're going to do something
with the key and
something with the value.
And so we're going to
take that original key
and call it here and update
the state to be that value.
And so for those of you haven't
seen this notation before,
this basically means
evaluate this expression.
And whatever it evaluates
to, cast it to a string
and that's going to be
the key of that object.
And so in this handle update
function, we pass it a key first.
And so imagine we want to do the handle
name change rather than doing this,
we can actually do handle name change
is equal to this dot handle update.
And we're passing it a key called name.
Well what does that return?
We can go ahead and
evaluate in our head.
So handle update is going
to be invoked with name.
And so you're basically passing
in name here, as the key,
and replacing it down here.
And so this will actually return
a function that is a value.
And what does that value do?
Well it calls this dot set state.
What does key evaluate to?
Well it's just name.
And it sets it equal to that bell.
And as you noticed, this, is
logically the same as this.
So here all we're doing is having
a generic updating function that
takes some sort of key.
And when we invoke it, it returns
a handler that takes a value
and sets the key, whatever
we pass it, to be that value.
And so certainly here
we could start to do now
handle phone change is
this dot handle update.
Let's actually name handle
update to get handler.
So slightly more informative.
We're getting some sort of handler.
Phone.
And so this is slightly better but,
again, for 100 different inputs,
we're still going to have
100 different handlers here.
And so why do we have to do it here?
We don't, really.
We can actually, down here, we can
say for this text input called name,
rather than doing this
dot handle name change,
we can actually just do this dot get
handler down here and pass it the key
that we want to update.
And that's going to return
a handler that takes a value
and updates this key to be that value.
And so for phone here, we can also do
get handler and just pass it a phone.
And that will go ahead and
create a handler for the phone.
And so rather than having a bunch
of different methods or properties,
that handle, each of the
different keys for the inputs,
we can actually just define one
generic one up here and then
go ahead and do it.
Actually, there's a
small bug actually where
they should be returning that function.
But rather than doing that, we can just
use the shorthand notation like this.
So rather than having a single line
return, we can just use the shorthand.
Because arrow notation,
it just implicitly returns
whatever is after the arrow.
So this is saying, this
takes a key, and it
returns a function that takes a
value and calls dot set state.
And so if you ever see
something that looks very weird,
like a bunch of arrows pointing.
It just means this, when
invoked, returns a function.
Which may, in turn, return a function.
However many arrows are just
the functions that are returned.
But here this is just saying, hey,
to get a handler pass me a key,
and I'll return you a handler.
A function that takes a value
and invokes this dot set state.
So hopefully that answers
the question in Slack.
And so what's the difference?
Which is better?
Well it depends.
In this example with the get
handler, when we render down here,
it's actually going to have to
invoke that get handler function n
times for n inputs.
And so that means, if
we have 1,000 inputs,
it's going to have to evaluate
that function 1000 times
in order to get the handlers.
And so if we instead define
those as class properties,
rather than invoking get handler
1,000 times for every render,
it does it once when it
creates the function.
And then every render, it already
has those class properties.
It can just pass those straight through.
And so even though using this
get handler generic function,
it's syntactically nicer, it's
not necessarily more efficient.
In fact, it's less efficient
than defining all those handlers
as class properties.
And so whether you use a bunch
of different class properties,
or you use get handler here,
depends on what you care more about.
Do you care more about efficiency for
reading and how nice it looks to read?
Or do you care more about straight
up efficiency and performance?
Of course, there are ways to do both.
And if you're curious, go ahead
and post your question in Slack,
and I will answer it after the lecture.
But let's go ahead and move
onto the next topic for now.
So debugging.
So there are a few
different ways to debug.
React and React native.
Those are the React errors and
warnings, Chrome developer tools.
Or you may see some online documents
referring to those as the "Devtools."
This thing called a
React native inspector.
And this library called React dev tools.
And so I'm curious to know how you
guys have been debugging thus far.
Go ahead and post in Slack your
various workflows for debugging.
I personally like to leave a bunch of
console dot logs all over my files.
And then go ahead and just look, oh,
that's what the value of that variable
was at that time.
But that's probably not
the best way for debugging.
There are actually a bunch of
tools that can do that and more.
And one is React errors and warnings.
And so you have this thing
called console dot log,
but it turns out that console
object has other functions too.
And so if you call this thing called
console dot error, what happens
is you get that full page alert.
And so you've seen this a few times
in lecture if we have an error,
or if we trigger something In
React that causes it to error out.
And so you saw earlier when we had the
infinite loop in component did update.
And so we can go ahead and just trigger
that manually by doing something like,
in render we can just
say, console dot air.
This is a full page alert.
And so now when we go
ahead and render that page,
we see a whole red alert
with our error at top.
And it also nicely gives us
a dump of the whole stack.
So what were the functions that
were called in order to get
to that console dot alert function.
So another way to trigger this
is also to just have an error,
to throw an error.
And so we can just do throw new error.
And when we throw that error,
it's actually get caught by React
and shown as this function,
as this big red alert box.
And, again, you see
the stack trace where
it was called in the add conduct forum.
So this is probably a very,
very aggressive way to debug.
And probably not the best way if
you're playing with your application
to just be greeted by a big, red alert.
So there are also less aggressive
ways by using these warnings.
So a lot of libraries actually
use either these full page alerts
or these warnings to warn you or to
alert you if something has gone wrong.
And so where have we before
seen yellow banners pop up?
Well it happens in prop type.
So if we define some prop
types for our function.
And if we don't get the
prop that we're expecting,
that prop type's library
written by [? Facebook ?]
will give us a little warning.
It says, hey, by the way, we
were expecting a different type
for the props and we got this.
And so that shouldn't
really be a big error,
but they're just warning you, hey,
by the way, this is happening.
And how do they do that?
Well, they call this
cancel dot warn function.
And so, say, we want to
just do console dot warn.
This is a less aggressive warning.
And so when that gets called,
we just get a small yellow box
at the bottom that's letting us
know that a warning appeared.
Again, maybe not things that you
would use in your application.
But if you're writing a library
to be used by somebody else,
you might want to warn them if
they're using your library wrong.
Or throw an error if
an error does occur.
The caveat with these warnings is that
they don't appear in production mode.
And so if you have warnings, and
you go ahead and deploy your app
to the app store running in production
mode, those warnings will not appear.
So this is not necessarily super useful.
So what's a better way to debug
rather than leaving console dot logs
or leaving console dot
errors or console dot warns.
Well maybe we should
use the Chrome Devtools.
And so for those of you who have
ever written web applications before,
you might be familiar with these tools.
So Google Chrome has
amazing developer tools.
Namely the debugger.
And we'll take a look
at that in a second.
But if we're running a React
native application, how the heck do
we get Chrome Devtools to work?
Isn't Chrome a web browser and aren't
we trying to write mobile apps?
Well if you remember
back to early earlier on,
we know that we can just run
JavaScript in any Chrome tab.
We know that we can also run JavaScript
maybe in our terminal using Node.js.
But how do we run React
native JavaScript in Chrome?
Well, if you remember back, there
are actually two separate threads,
one for native and one for JavaScript.
And how do they talk to each other?
Well they just communicate
asynchronously through a bridge.
Just sending messages back and
forth like, hey, I need a button.
And then the native will
give you that button.
And when it's clicked, it'll say, hey,
JavaScript, my button was clicked.
But does that mean they need to
be running on the same device?
Not necessarily.
Since the way that
they're communicating is
just through this
asynchronous message sending,
that means we can run the native
thread on that native device.
And you can run the JavaScript anywhere.
We can run it on the device.
We can run it in a Chrome tab.
We can even run it on
somebody else's computer.
And so we can actually go
ahead and do that built
into the React native application here.
So I can go ahead and
say, shake my device.
So I can go to hardware shake, shake
gesture, which is control command z.
And it goes ahead and
brings up this menu.
And I can say, hey, I want to
debug my JavaScript remotely.
So if I click that, I get
a new Chrome tab open.
Then we just move this
to a separate window.
So I now have a separate window.
And if you look at the title here,
it's saying React native debugger.
And so the React native
JavaScript code is running
as a web worker inside this tab.
Or in other words, the JavaScript
is executing inside this Chrome tab.
And I can go ahead and
open the developer tools.
And I can see this.
So if I go into debugger
worker, local host
1901, which is where this is running, I
can go ahead and see all of this code.
And if you look at something
like add contact form,
you see exactly what we have
been working on recently.
And so you see that get handler.
Let me make the text bigger.
You see things that we've
written very recently,
like that get a handler function.
That takes a key and returns a
handler, a value, in that set state.
And we can go ahead and use the power
of Chrome's debugging tools to go ahead
and debug our app.
And so let's go ahead and throw
a bug in our app and try to find.
So let's go ahead and rather than using
this dot state dot name dot length
to check name, let's try to
enforce that the user have
both a first name and a last name.
And so let's use that in order to
decide whether the form is valid or not.
And so how might we do that?
How do we check to see
if the user has given us
both a first name and a last name?
We can just count how many
words are there, right?
So let's go ahead and do
something like content names
are this dot state dot name dot split.
And then split that every space.
So for those of you who've
never seen this dot split,
it basically says with a
string, given a string,
every time you see whatever argument
I pass in, go ahead and return
to me an array that's tokenized
by that character or string.
And so in other words, every
single time I see a string,
give me the tokens around those strings.
So in hello space world, give me an
array containing hello and world.
And so here, let's just assume that
the user gives us a first name space
last name.
And now names will be
an array of two names.
The first name and the last name.
And so now let's check if names dot
length is greater than or equal to two.
Then let's call that a valid name.
Now down here let's get rid of all
of those extraneous text inputs.
So delete here.
And now we're back to
just those two things.
And now we're using
that get handler method.
So let's go ahead and
try to add our name.
And make sure that the
validation is running.
So disable this dot state is valid form.
The opposite of that.
So now hopefully we're in the
state that we were before.
Where the form starts invalid, and
if I give it a valid phone number
and a valid name, is it getting called?
It must not be.
Component did update.
This dot validate form.
So let's see if it's
actually getting called.
And how might we do that?
So time to debug.
So for those of you who've never used
the debugger, what it allows us to do
is set breakpoints.
And what our breakpoints?
Well, it's a point where,
if this code path gets
hit, meaning if this code is about
to get evaluated, stop and give me
a chance to look at some things.
And so we can go ahead and
in that Devtools window,
we can say, hey, right before
this gets called, let me stop in
and inspect some things.
Let me take a look around.
And so by clicking on these numbers
around here, some things get called.
You see these blue highlights appear.
And that is me adding a breakpoint.
And so now, right before this line gets
executed, it's actually going to pause
and let me look at some things.
So now let's make sure
that gets triggered.
OK, so as soon as I change my
name here, it triggered this.
And it says pause on breakpoint.
Now I can see the call
stack, meaning what
are all of the functions called in
order to get me to where I am now.
And so you see a lot of
this is React internals.
But you see something that
looks like this dot validate
form, which is from that add
contact form that we were writing.
And so it makes sense that those were
the most recent functions called.
And we also see scope.
We see all of the
variables within our scope.
And so, if you remember back to earlier
lectures, we talked about scope.
And scope being all of
the variables that I
have access to at any given time.
And we see that names is currently
undefined, which makes sense.
We haven't evaluated this line yet.
And we see some closures, which as
you remember back a few lectures ago,
are functions that still have
access to all of its parent--
the variables in scope of its parent.
And so we see this add
contact form, which
is this form that we're inside of.
And so we see all of
the global variables
as well, which there are a ton.
But let's look at what
we really care about.
We really care about names
right now which is undefined.
And so we can say, hey, rather
than-- we can click this button
to resume the execution.
So it'll just keep going.
Or we can just step over
this next function call.
Or in other words, go to the next line.
We can also choose to
go into the function.
If we want to, if we think, oh,
it's not my code that's breaking,
it's actually this dot
split code that's breaking,
I can choose to see how
dot split is implemented.
But I think it's a safe assumption
that the bug here is mine and not
the JavaScript's.
So I can say, OK, let's
go to the next line.
And so now we see what's highlighted.
We know that line 57 has
just gotten executed.
And we're about to execute line 58.
And so now what is in scope?
Well names get updated.
Now names is Jordan space hayash, which
is what we were writing in the input.
And so now we can go ahead
and step through our code line
by line to see where the bug is.
And so now we can go ahead and
say, OK, we're checking phone,
we're checking phone's length, and
we're checking names dot length.
And so this worked.
And so now we're on line 59.
And it's about to say,
is form valid true.
Cool.
Click next and then
what is happening now?
So now, it updated everything.
And now we're in the next cycle.
So it was validating the form again.
And so we can just
keep clicking through.
And now the component
did update is done.
And so this dot validate
form is finished.
And now it's going to finish updating.
And we can just hit play.
It looks like we're stuck in a loop.
What's happening over here?
OK.
So we saw that the problem
was not in this validate form.
Names was getting set to be what
we thought it was being set to.
And we saw that this
dot set state is form
valid is getting updated to be true.
And so the bug lies somewhere else.
So is form valid is getting
updated as expected.
And so down here, we see why
isn't disabled getting updated?
Well this dot state is
valid form does not exist.
What are we calling it?
Well we're calling it this
dot state dot is formed valid.
So we see up in the state,
we're declaring is form valid.
We're updating here.
And that is what we should be looking
at, rather than is valid form.
Cool so we caught the bug.
And now we can ensure that it works.
Great, now it worked.
But let's say, oh, I made a typo.
Let me go back.
Hey, wait a second, is there
a first name and a last name?
No, but it's saying that
the form is still valid.
And so now we have another bug.
And so let's now go use
Chrome Devtools again
to figure out what the bug is here.
So let's again set a breakpoint here.
And go ahead and find that case.
OK.
And now when we hit a space,
now we're back to where we were.
On the case that has
been tripping us up.
And so now, we're about
to execute line 57.
We see names is undefined.
And so let's go ahead
and execute that line.
And now we see names of length 2.
And what is that array?
Well the first name is Jordan and
that second string does not exist.
And so names dot split is
doing what we're telling it to.
We're saying split at every space.
And right now, this dot state dot
name, we could dig for it in here.
So this dot state dot name
is Jordan space, which
isn't a first and last name pair.
But the way that we're defining
whether or not a name is of length two
is getting fired.
So, again, this dot state
dot name is Jordan space.
And we see that name dot split at
the space is giving us two entries.
Jordan and empty stream.
Because it is splitting at the space.
And what's after the space?
Well, an empty string.
And so we see that here, this is
returning true when it should not be.
And so now we can go
ahead and fix that bug.
So rather than saying names dot
length is greater than or equal to 2,
what do we have to do instead?
We should also check that names--
the last name exists.
And so we can just do, hey, remember
back to what are all the falsy values.
Well empty string is a falsy value.
And so if names bracket one, meaning
the last name, if that's an empty string
that shouldn't be an accepted value.
And so now let's go ahead
and remove that breakpoint.
So we are in the file
called add contact form.
Let's go ahead and
remove that breakpoint.
And now we see that
if I do Jordan space.
Well this isn't a valid phone number.
Jordan space, it's still erroring.
Did we remember to save?
We did not.
So, again, phone number, Jordan space.
And it is not a valid form.
And so we can use
Chrome's debugger tools
to go ahead and step through
our code line by line
and see all of the
variables that are in scope.
And so we can catch bugs like
this, where what we think
is the case that we're
looking for, might not be.
And actually it's still slightly buggy.
Can anybody see the bug?
So if we have a leading space,
we're only checking the last name.
We're not making sure the
first name is existing.
And so we can fix that real quick.
We can say, oh names
zero also needs to exist.
And we'll call that good enough.
So now with a valid phone number,
space [? Hayashi ?] doesn't work.
Space space doesn't work.
And it only works as soon as we
start to add that second value.
And so another great thing about
Chrome developer tools is the console.
And so I said earlier how
I love console dot log.
And let's actually look at a case where
console dot log works in the browser.
But it might not work
in other environments.
So let's go ahead and
stop remote debugging.
And so now we're running the
JavaScript not in the browser.
And so let's go ahead and every
time we want to validate the form,
let's just console dot log the form.
Or this dot state.
So now when we're changing the state,
we see things are updating over here.
And so the logging of the
JavaScript is getting piped over
to the [? expo XTE. ?]
And we see down here,
when we console log
this dot state, we see
an object that has all of
the keys and values of state.
Where is form valid is false, name
is Jay, and phone is empty string.
But what happens if that
object is pretty complicated?
What happens if that object has a cycle?
So now we're sticking inside
of state this is equal to this.
And so this here, is going
to have this dot state in it.
And so this dot state dot
this, is going to be this.
Do you see how this is going
to start becoming circular?
And so this is called circular JSON.
Or JavaScript object that
self-references itself.
And so now if we start to type anything
here, things just aren't going to work.
So this is now a valid form.
But it's not showing as a valid form.
Why?
Because this initial console dot
log is still trying to happen.
And so you notice that nothing
here is getting logged.
It's because it's still trying
to figure out what to log.
It's going through that infinite cycle.
But, it turns out if we try to actually
do this in the browser instead,
so now we're back here.
Say we type something over here.
It works.
And so Chrome's logging abilities
are actually phenomenal.
And you can see that it gets
printed four times because we
changed the value four times.
And what do we see here?
We see is form valid false, name,
test, phone, empty string as expected.
And then we see this.
Which has in it, this
dot state, which has
in it this, which has in it this
dot state, which has in it this.
And this can go on forever.
And so the logging abilities of
Chrome are actually pretty incredible.
As are the debugger.
And so this is a great
way to go ahead and debug.
You can step through
your code line by line.
You can have these pretty complex
console dot logs and it all works.
So what happens if the
bug is not logical?
What happens if the bug
is rather in the layout?
So let me introduce a small bug.
So let's actually go ahead and
stop running this remotely.
So now we have our form.
It's at the top like it
was at the beginning.
And say now we want to try
to get it to the center.
Let's try to center
this form vertically.
The way you would do that would be
justify content into the center.
And that, in theory,
is going to take all
of the content of the container, which
is what we're calling the wrapper,
and move all of its content
to the center of its height.
But as we see, it's not
moving down to the center.
And those of you--
some people may see instantly,
oh exactly what's wrong.
But it's pretty not obvious.
We have it supposedly centering.
But it's not moving to the center
of the screen like we're expecting.
And so this is not really something
you can debug using the Devtools
or console dot log, because
it's not a logical bug.
This one has to do with layout.
And so it would be really great if we
could just inspect all of the layouts.
Fortunately, we have something
called the React native inspector.
And this is analogous to that
Chrome element inspector.
So those of you with a web background,
probably use that element inspector
where you can see all
of the Dom elements,
and see exactly where
they are on the page.
It also allows you to see data
associated with those elements,
like margin, padding, size, et cetera.
And so we can actually go ahead--
we can use that tool to figure
out what's going wrong here.
And so, again, if we
shake our device, we
can see this toggle
element inspector button.
And if you click on it,
we see this UI pop up.
It says tap something to inspect it.
And so if we go and click this inspect
button down here, that will toggle on.
And so now we can click
anywhere, and we can
start to see all of the styles
associated with something.
So say we click on this
input, we see down here
this text input is in add
contact form.js, which
is exactly where we defined it.
We see all of it style attributes.
It has a border width of one.
It has a border color black, mid
width 100, margin top 20, et cetera.
And we see exactly how it's laid out.
And so imagine that this was a box.
We see its margins.
So it has a margin top of 20.
Bottom, there's no margin.
And on either side it's 20.
We see some padding.
And we see the dimensions
of the element itself.
And so that's helpful
information as we're
trying to determine how are we
trying to lay out our UI elements.
And so what's the buggy part?
The buggy part is that form that we say,
oh, it should be centering its content
but it's not.
And so let's go ahead
and find that form.
The submit button.
There's that form.
This is the keyboard avoiding
view in the add contact form.
So it has a background color
of white, has a padding top
of 20, justified content center,
padding bottom 0, all these things
that we defined in the style.
But the height isn't
what we're expecting.
We're expecting it to be full
height, but what's being highlighted
is only this here.
And so blue refers to the
height of the element itself.
Green refers to its padding.
And so it is centering its content.
If you imagine the height is here,
everything is perfectly centered.
It's just the height is not
what we were expecting it to be.
We thought the height was going to be
the full and so center should be here.
And so we found our bug.
The bug is that we just need
to make the height full height,
so that when it's entering
its content, the content
is in the center of the device.
Not the center of this view, which
is not as tall as we thought.
And so if you remember back to section
when you guys talked about Flexbox,
we can see the bug.
So a container should be filling
all of its available space.
We should say flex 1.
So grow as much as you can.
And now, it's centered again.
And how can we confirm that?
Well, we can click on
that add contact form
and now we see it's
blue all the way down.
And we see the height
is now what we expected.
And so for testing UI elements and
seeing exactly how they're laid out,
their size, their padding,
their margin, the inspector
is a great tool to be able to do that.
The caveat with this
inspector is that doesn't
allow you to live edit these elements.
So when I wanted to
change the flex to be one,
I actually had to go
do that in the source
I had to rebundle the JavaScript,
have the bundle get sent to the app,
and have app reload.
It doesn't allow me to just hop in
there and change things at will.
Since I'm talking about
that, you can probably
guess there is a tool to do that.
That tool is called React dev tools.
This allows you to inspect the
React component hierarchies,
so you can see the entire React tree
including the components, the props
and its state, style.
How do we run this?
So first we have to install it.
So if you run this command npm
install -g, which stands for globally.
Install this library
called React dev tools.
And so we can go ahead and do an
npm install -g react dev tools.
So I already have it installed, so
it's going to happen fairly quickly.
But for those of you at home
who don't have it installed,
you can go ahead and
install it globally now.
And this will allow us to go ahead
and use this tool called React dev
tools anywhere.
And so when we want to run it, all we
have to do is type React dev tools,
and it will open up, it will
run the command, and open it up.
And what that does is it allows
us to make live edits to style,
live edits to props, et cetera.
And if you want to read more about
it, you can go to its Github page.
It's also maintained by Facebook.
I mean, it's a brilliant tool.
So go ahead and give it a shot.
So notice we just run
it as React dev tools.
We don't have to tell
it where our app is.
And it will just go ahead
and find our application.
And so now we see this.
We see app container.
And if we start to unfold
these things, things
are going to start become
pretty recognizable.
So we're starting to see
things that we've named.
Add contact form, app, text
input, text input button.
And as we hover over them, you
can see them highlight over here.
And how is that working?
Well it's actually working
with the inspector to do that.
And so now let's go ahead
and reintroduce that bug.
Let's go ahead and reintroduce
that bug into add contact form.
We can get rid of that flex.
Let's get rid of justify
content center as well.
And so now we're back to where we
started, with that original bug,
where we want to center this and
we're going to have to figure out how.
And so let's do that in
the React developer tools.
And so you can see that this tree
here matches up exactly with the tree
that we've defined in our code.
And this is actually
the react element tree.
And so we can find that
keyboard avoiding view,
and we can see the style here.
We see background colors
FFF and padding top is 20.
And that matches with exactly
what we have here where 20 is just
getting the value of this variable.
And so now we can actually
add inline whatever we want.
We can say, right now if we highlight
over this with the inspector on,
we see that this keyboard
avoiding view is only this tall.
It's only as tall as its content.
And so let's first get that to fill.
And so we can go ahead and just say,
oh, I wonder what's going wrong.
Let me add flex one.
And so now, all of a sudden,
keyboard avoiding view
is filling all the available space.
Which is exactly what
we're telling it to do.
We're saying, flex grow until you
fill all of the available space.
So now we can go ahead and
center all of its content.
And we can say justify
your content to the center.
And you see it jumps immediately.
And so this also allows us to
inspect all of our components.
State, our props, anything
that we care about.
And so right now inside our form
so, say we can't find our form.
Say it's buried deep.
We can just go ahead and search form
and we find or add conduct form.
And you can see its subtree here.
Right now its state is saying is
form valid false, name, phone.
And as we change things, you can
see things live update over here.
And so as the state of the app changes,
you can see it update in the dev tools
here.
And so this is a great
tool to make sure what
you think is happening to the state is
exactly what's happening to the state.
And you can even override this.
Let's say the phone should be this.
And it will go ahead and
set that state for you.
So this is all around great tool for
inspecting state, setting state, making
sure things happen when you set state.
You can go ahead and inspect style
and go ahead and quickly prototype,
so that you don't have to type all
of your style into your text editor.
You can just see exactly how it's
going to impact your application.
And then if you like what you
see then go ahead and then
commit that and save
it in your text editor.
You can also see what
props are coming down.
You can ensure that you're passing the
props that you think are passing down.
I mean, so this is
just a great tool to be
able to see exactly what React knows.
So any questions on React dev tools,
the inspector, or Chrome Devtools?
So let's move on to our last topic.
So external library.
So how did we get React dev
tools onto our computer?
We use this thing called NPM
And React dev tools is actually
just an external library,
external code that we're
bringing into our own project.
So libraries are code written
outside the context of your project,
that you can bring
into your own project.
And so these can be written by you,
they can be written by other people,
or they can be written by companies.
Or anybody really.
And so stuff like React is a library.
It's a library written by Facebook
that we pull into the project
that we're writing, just because
we want the ability to use
all the features of React without
having to write the code ourselves.
Imagine every time you want to
write a React native application.
Imagine you have to write
all of React native.
That would not be fun.
And, in fact, it would
not be fast at all.
Which is the big benefit
of writing in React native.
And so what we can do is we can
actually use other people's code
and bring that into our own projects.
And so since React native
is just doing JavaScript,
it's writing JavaScript
and evaluating JavaScript,
you can add any JavaScript
code to your project.
And so any library written
in pure JavaScript,
you can just pull in and use
that code in your project.
And so there are plenty of great tools
that give you a bunch of functions
that you can use.
So like Lodash, Underscore, Ramda.
These are all just tool belts
that give you access to functions
that you might use very often.
And you can just go ahead and pull
all that JavaScript into your project
and use it as you see fit.
The way you that you
install these things
is by using NPM, or
Node Package Manager.
For those of you who are not
familiar with package managers,
is it allows you to just--
manages the packages for you.
These packages,
synonymous with libraries.
And so you can say,
rather than me having
to go and find where the
source code of React is,
and download it, and then
upload it into my project,
and then go ahead and
import into my project.
Oh no, versions don't match.
That's all taken care of for
you buy this thing called NPM.
And so if you say, hey, I want React.
You can just say, NPM install react.
It will find where React
is located for you.
It will download it for you.
It will keep track of the
correct version number for you.
And then you can just go ahead
and import that into your project.
And how does it keep track for you?
Well, that's what that package.json is.
So every single project that we've
seen before, there's this thing
called package.json.
And inside it, there are a
few different key value pairs.
And one important one
is called dependencies.
Dependencies, or in other word,
what other code do I need in order
to make this application work?
Obviously I'm going to need React.
Because every single file,
the first line is what?
Import React from React.
Well, where is React?
Well, it's right here.
And so what this
package.json does is it says,
hey, this is the exact
version of React that we need.
NPM go find that for me,
go download it for me,
and keep track of where it is so
that I can import it into my project.
What else do we need to run?
Well we need Expo and
we need React native.
And if we need other libraries, we
need to make sure that they're here.
So that when other people
want to use our project,
they have those when
they want to install.
And so many of you have probably
used this command called NPM install,
and now you know exactly what it does.
Is it reads through
all your dependencies
and goes in find them and
downloads them for you.
And so now let's say in row, we
want to define some prop types.
So we've seen before, this line,
import prop types from prop types.
And then we go how do you use it.
We can say row dot prop types
is this object where we're
expecting a name, which is a string.
And we're expecting phone,
which is also a string.
So we've gone ahead and imported
this thing called prop types
from this library called prop types.
But what is prop types?
Well this is actually going
to work, believe it or not.
And it's a little bit
strange why it works.
The reason that it works is because
other the libraries that we're
importing, also import prop types.
And so we it just happens to be
the case that prop types is already
installed for us.
But we're not guaranteed that it's
already going to be installed first.
So what we should do is
NPM install prop types.
Which is saying, hey, in
this project, we actually
need this external
library called prop types.
NPM go install it for me and
then make sure to note it.
And so now, if you see,
in our package.json file,
prop types was
automatically added for us.
And so NPM is this great software
that just manages all of our packages
for us.
It finds what we need, and installs
it, and keeps track of version numbers.
And it makes sure that whoever is using
my project, when they type NPM install,
they get the dependencies that
they need to run my project.
And so if you're using an
NPM version before NPM 5,
and so you can tell what NPM version
you're using by doing NPM --version.
I'm running 5.6.
Since that is newer than NPM 5, I don't
need to use this dash dash save flag.
Before NPM five, if you
just did NPM install,
it wouldn't add it to your package.json,
and now that's the default.
But if you are using an
older version of NPM,
then you're going to have to
use that dash dash save flag.
Or if you want to install
a library globally,
so like we did with React tools, you're
going to have to use that dash G flag.
And what that does is it gives you
access to that library everywhere
on your computer.
And so the reason that
we could just type
React dev tools was at the command
line is because that package
is installed globally on our computer.
The reason it wasn't working is
because there's another one running
on this separate window.
And then, lastly, all we need to do
is just import into to our project.
And so a line that we see all the
time is import React from React.
And what that does is it says, hey,
go get that package called React,
import its export default or its default
export into our project, name it React.
And now I'm free to
go ahead and use that.
And so if I want to use any
other library, all I could do
is NPM install that library, make sure
that it's added to our package.json,
so other people who use
our project can go ahead
and install that for themselves.
And that's done automatically by NPM.
And them we can go ahead and
import that into our project
and use it as we please.
And so in future lectures, we'll
see other JavaScript libraries
that we'll be using.
So React navigation we'll see very soon.
And we'll see other
libraries like Redux.
That's just us using other
people's code to our benefit.
We don't have to re-implement
other people's projects.
We don't have to reinvent the wheel.
We can just go ahead and build
upon what other people have
written on our own app.
And so a lot of non-replicated
effort on our part.
So next week we'll go ahead
and dive into navigation.
We'll see how, right now we're using
the if the state says to show the form,
go ahead and render a different page.
Otherwise render original page.
Next week we'll see exactly how
we're going to do that scalably.
Because right now, if we
have 10 different pages,
we don't really want, if this
page is visible, render this page.
If this page is visible,
then render this.
We're going to see a library that allows
us to better navigate our application.
And it will give us the ability to
have things pop on top of each other,
go back and forth.
And so we'll dive into that library.
And so we actually
have a guest lecturer.
The people who wrote the library
itself join us next week.
Next lecture.
Next week is spring break.
And so we have that to look
forward to in the coming lecture.
So thanks everyone.
