0% found this document useful (0 votes)
31 views16 pages

Lecture 4

Uploaded by

dis
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
31 views16 pages

Lecture 4

Uploaded by

dis
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 16

[MUSIC PLAYING] SPEAKER 1: Hello, and welcome for lecture four.

This week, we'll be


covering lists and user input. And so in the previous lecture, we looked into React
Native. So we started diving into the components that they give us. We looked at
how to style these components. We looked at how to handle some events, and how that
differs from reactive web. We talked about a couple of different types of
components. One, being stateless functional components and the other being React
components with their life cycles. We looked at Expo, which is a library of-- a
bunch of tools around React Native that allow you to develop much more quickly. We
looked at how to import and export things from packages and modules. And then
lastly, we looked at prop types, which are library given to you by React that
allows you to keep track of the different props, now that you're passing two
different components. So this week we're going to talk about React Native much more
deeply, and in the context of contacts. And so we're going to write a simple
application, whereby we can add contacts to a list and display those for the user.
And so what might we want to implement in doing that? Obviously, we'll need some
sort of way to add users, which we'll do towards the end of lecture, but also we
have to have some sort of way to display those users. So if you can imagine on your
phone, if you want to keep track of your contacts, you want to be able to see all
of them and scroll through all of that. In order to do that, we need to use what
are called lists. And so in web, browsers will automatically become scrollable. If
the content is greater than the window height then the browser will take care of
the scrolling for you. Unfortunately, this is not true in React Native. For mobile,
we actually have to do that manually. So there are a few different components that
allow you to do that. The most simple of which, is called a ScrollView. And so it's
just like a normal view, except you have the ability to scroll. We have something
that was called ThisView. If you see that in some source code or maybe some
libraries that you're looking into, that used to exist. It still exists, though it
is deprecated and is not actively used anymore. To replace those, there are a
couple things called FlatList and SectionList, which we'll be looking into in a
little bit. So firstly, we have this thing called a ScrollView. So this is the most
basic scrolling view. And so it will actually render all of its children before
appearing. And so, if you can imagine, say you have a view that has a bunch of
children in it. If it overflows the page, unfortunately you can't see the content
that's beyond the window because unlike in web, mobile apps don't allow you to
scroll down. But with the scroll view, it will actually do that. It will render all
of it's children and then allow you to scroll back and forth. And so let's dive
into how that is actually used. And so if you saw on Slack, I posted a link to the
source code, it's also linked on the web site. And today, we're going to be working
through a simple application, and there is a bit of code that is posted right now
that will allow you to follow along in class, if you so wish. So first thing that
we're going to do is look into how we actually create contacts for the first time.
So if you look into this file called, contacts.js, you have a bunch of things in
there. At the very top, we declare this constant, called number of contacts. And as
you'll see in a second, I wrote this little thing that will allow you to just
generate a bunch of random contacts. And so it pulls from a list of long first
names. And so on line three, here we see that there are a bunch of hard coded first
names. If you scroll a little bit farther down, you see a long list of last names.
So the functions that we'll look at in the second will actually pull from that
array of first names, and that array of second names of last names. And so some
sort of function that we might want to have when we're generating random names is
some sort of function that generates random numbers. And so you see here, we have
some function called rand, which will generate a random number between some minimum
and some [INAUDIBLE]. So you can look into the math that's done here, but
basically, it's just a little bit of math that generates a random number from 0 to
1. Multiplies that by some scaling, and then scales it up to the minimum.
Basically, it does a little bit of math and gives you a number between a minimum
and maximum. Next, we have a function that will actually generate a name. And so we
have this thing called generate name, which when invoked, you see this, what's
called a template literal, which allows us to do some JavaScript, evaluate an
expression, and actually add that to a string without having to do some string
concatenation. And so with backticks and this thing, a dollar sign, and brackets,
we can actually throw in line a JavaScript expression, which will get evaluated and
automatically add this to a string. And so we see here we're invoking this random
function with the number of first names that we have minus one, which will give us
a random first name. We do a similar thing with the last name and then use this
template literal to give us a random name. So first name, space, last name. We see
a similar function down here, that will allow us to generate a random phone number.
So we see that random function again, giving us a number between 100 and 999. So
basically, some random three digit number. Again, another random three digit
number, and the random four digit number with dashes in the middle, which will give
us the 10-digit phone number. We have a function down here, which will create a
contact. And so the way that we're defining your contact is by giving it a name.
The way that we get a name is by calling that generate name function and a phone
number. And the way that we get a phone number is just by invoking that generate
phone number function. And so when we invoke this function called, create contact,
we're given an object with a name and a phone number, and that's what we're going
to consider a contact for our examples. I also wrote a little helper function there
that we'll use in a little bit, which allows us to alphabetize lists. And so it's
just a way of comparing a couple of names. So if we pass a couple of contacts, we
just extract the name here, extract the name of the second contact, and just
compare them. So see which one comes first in the alphabet, which will allow us to
do some alphabetizing. And lastly, we have this function, which allows us to add
keys. And basically, what we're doing is we're passing a value in a key. We're
inserting the key. And so we see a couple of new things here. One is the shorthand.
And so if we have something like that, that's actually shorthand for something you
may do a lot, which is this. So the people who maintain JavaScript, who have made
an [INAUDIBLE] actually, notice that this is something that you see very often in
code. And so rather than repeating a key and its value where the key is the name of
a variable, you can actually do that in line and just by removing the second half,
it automatically fills that in for you. We also see this dot, dot, dot, val. So we
talked about a little bit in previous lectures doing what's called array
destructuring. And so by doing dot, dot, dot, in array name, it will actually
explode that array into a new array, which is helpful for when you want to
concatenate two new array's immutably. It just happens to be that this thing also
exists for objects, and so one way we could implement this function would be by
hard coding all of those key value pairs. So if we want to do const
addKeyToContact, if it were a function that takes a contact and a key, we could
actually do the exact same thing by first doing key gets whatever the key was
passed. We could also-- we know exactly all of the key value pairs in a contact,
right? We have name gets generate name and phone gets generate phone. So we know
that every single contact is going to have a name and a phone. And so we can
actually just hard code that in. We can say the name gets the contacts name, and we
can do the phone gets contact phone, which is fine. It does exactly the same thing
as this bottom function does, assuming that contact is in the shape. The downside
is, what happens if we start to add new keys to contacts? Say we added a first
name, last name rather than name, or say we added an address, or a bunch of other
fields, we'd also need to remember to go add all of those key value pairs into this
add key to contact. And so the maintainers of ECMAScript realized hey, this is
something that we're going to be doing very often, so why not have some sort of
shorthand to do that? And so what they gave us was this. It's called object
destructuring, where you do dot, dot, dot contact and that will actually take all
of the key value pairs of contact and automatically do what I had there before for
you. So this is a pattern that you see very often. So say you wanted to clone state
or say you wanted to clone a bunch of props. Those are also in the shape of objects
and so this dot, dot, dot notation allows you to do that easily. And so we use that
here and add keys so that when we're past the value of an object, we can actually
just clone the object very quickly and append the key. In the very final line, we
see what we are exporting as the default export for this module. We see, create an
array of length, number contacts. And so at the very top, rather than hard coding
in some value here, we just said, hey, give us some sort of number where we want
that number to be the number of contacts that we eventually export, and then we go
ahead and use that there. And then we go ahead and map add keys to it. And so array
dot from
is a function in JavaScript where it allows you to take something of array like
shape and turn into an array. It takes another argument, which you map over these
things. And so by passing in length NUM_CONTACTS, that's the shape of an array
object. Because every single array has a dot length value, and so by passing in
this object called length NUM_CONTACTS, it's a shorthand way of just creating an
array of arbitrary length. We then map over it create contacts. And what does
create contact do? Well, it doesn't care what objects are passed to it, and so in
this case when we use map, we really don't care about what the value of the array
values are to begin with because we're just going to replace those with random
contacts. And so by doing array dot from length of number of contacts, that creates
an empty array of length and number of contacts, which we declared at the very top.
We then map create contact over it, so now we have an array of length and
NUM_CONTACTS filled with random contacts. And then go ahead and map over that to
add keys, and we'll see why this is valuable in a second. So any questions on this
little helper file that I put together? Basically, all it does is create a length--
an array of length NUM_CONTACTS. So 1,000 here and then it goes ahead and fills
that with a bunch of contacts where we define a contact as a name and a phone
number. So let's go ahead and first try to add that to some sort of application
where we can display all of these contacts. And so if you go ahead and run the
project that I've linked to, all it is, is a blank screen that allows you to toggle
the contacts being shown. And so now, that's actually-- look at what the
application is doing. And so if you open up this application we see the usual
imports at the top. So we're importing React from React. We're importing a bunch of
views from React Native. One of those is ScrollView, which we'll be looking at in a
second. We see important concepts from Expo, which as we saw in a previous lecture,
allows us to have some padding for the status bar at the top. We're importing
contacts from contacts, which is the file that we were just looking at. And then
we're just declaring a new class called, app. And so the first thing that you see
that looks different than what we've seen before is this thing called, state. We've
talked about state extensively, but in prior lectures when we look at state, we
always do that in the constructor. There's actually another shorthand that we see
here that is very useful for when you want to use constructors that all they do is
add state. And so as we saw in previous lectures, when we were doing something like
binding an anonymous function like this to some sort of class property, we can
actually also do that with state. And so this is a shorthand, which actually will
compile down to this. And so as we saw earlier, all I had was state equals this.
And what happens when you compile this, is it actually compiles into this. It takes
all of the class properties that we declared and moves that into the constructor.
And so you see that we have this toggle contacts, that actually gets moved up into
the constructor during translation. And so we see this dot contacts, this dot
toggle contacts, equals some anonymous function, like this. And so when this
actually gets compiled, it all actually turns into this. But since we're not
actually doing anything in the constructor other than calling the super, then why
not just use the class properties so that it is easier to read? And so if you are
looking at other people's code or maybe reading libraries, most people actually do
something like this, just because it's slightly easier to read. And so we see
toggle contacts is a function that we defined, and all it does is it toggles the
show contacts Boolean, which we store in the state. And finally, we see render. As
we talked about extensively last lecture, components, their sole purpose is to
render things to the UI. And so the render function here is just returning a view
with a button that toggles the contacts. And right now, we're not actually doing
anything with that value, but we're actually going to turn this into an app where
we can actually show the contacts on the screen here. And so let's try to do this
in a way that we-- using things that we have learned in prior lectures. And so if
we wanted to display all of these contacts on the screen, how might we go about
doing that? Some previous lectures, we've learned a few different components. We've
talked about buttons. We've talked about text, and we've talked about view. And so
using those, we can sort of start to create this application where we can see what
contacts we have. And so using things that we've seen in previous lectures, you
would use a view and wrap a bunch of texts to show those contacts. And so right
now, we've imported contacts, which is a big long list of contacts, and we're going
to go ahead and display that in that view. And so how might we go from an array of
contacts to a bunch of people in that view? Are there any functions that we've
learned thus far, where we take an array and turn that array of values and turn
that into something like an array of elements? Yeah? AUDIENCE: [INAUDIBLE] SPEAKER
1: Yeah. Map would be a great example here. So what map does is it takes an array,
and for every single value in the array it runs it through a function and takes the
return value of the function and returns a new array. And so right now, we have
imported contacts from contacts, which as we saw, is just an array of people. And
if we are able to turn that into an array of elements, we can actually use React to
render those elements. And so let's actually do that here. So we can do contacts
dot map and what do we want to do for each of these contacts? Well, maybe we should
render some text to the screen. And so let's just start with this, where the text
is the contact's name. And we see that it's rendering. So I see 1, 2, 10, maybe 50
or so contacts, but when I try to scroll nothing happens because as we saw earlier,
unlike in mobile, when we have views that are larger than the viewport, there's
actually no way for React Native to automatically add the scrolling for you. And so
we have to actually have some additional components to handle that. And so as we
talked about, we have this thing called a ScrollView, and so this is the most basic
scrolling view, and it will render all of its children before appearing. If we want
to render an array of data, as we saw, we can just use that dot map function. And
so now, let's try just replacing this view with the ScrollView. So all we changed
was replacing view with ScrollView, and now, we have a view that scrolls. One thing
you notice, is that we have a warning at the bottom of the screen. It says, each
child in an array or iterator should have unique key property. So what does that
mean? So this is actually something that reacts uses for performance reasons.
Because if you can imagine, say we have a list of items. That list is Jordan and
David. So in previous lectures, we talked about this thing called the React's tree
or the React virtual dom. And what that is, is React's way of maintaining all of
its components that it's rendered in some tree like data structure. And so we might
have something like a list. And then within that list we have this thing called
Jordan and this thing called David. So in previous lectures, we talked about how
when we add something or when we rerender, React will actually recalculate this dom
and then only do what's necessary for a new rerender. So say we added somebody to
this list. So say we add Yowan to this list. In this example, it's pretty easy
because we have Jordan is where he was before, David was where he was before, and
now we just add Yowan to the very bottom. And so React can see oh, Jordan, David,
easy, let's just add Yowan. And so in this example, it's fairly easy to just tell
oh, we just added somebody to the bottom of list because the top two stayed the
same. But say rather than adding Yowan to the bottom of the list, say we actually
added him to the top of the list. So now when React does it's diffing, so when it
compares all of the nodes, it says, oh, we used to have Jordan in position one, and
now we have Yowan in position one. That's not good. We should update this to be
Yowan. What's in position two? Oh, position two is now Jordan. It used to be David.
We better update that. And now we see in the third position here, oh, that's new.
We better add David. So does anybody see why that might not be ideal? There is
actually a shorter route, right? Rather than replacing Yowan for Jordan, and rather
than replacing David with Jordan here, we could have just added Yowan to the
beginning of the list there. And so if you could imagine, if this list is 1,000
things long, it might not be trivial to know exactly where things should be moved
and where things should actually just be replaced or updated. And so React actually
implements this by using these things called, keys. And so how can we tell that
this Jordan is the same as this Jordan here? What if you have multiple people in
the list called, Jordan? And so in our example we have a bunch of contacts. What if
a few contacts have the same name? That might be true. We can pretty much guarantee
that multiple contacts won't have phone numbers, but there's no-- won't have the
same phone numbers, that is. There's no way for React to inherently know that oh,
this is a unique key in the object that we have here. And so what it has done to
solve this, is it actually uses this thing called a key. And so anytime we have a
list of data, React says, oh, one of the things in that-- one of the props that you
should pass for each of the things in the list is this thing called a key. And so
if we see here in this example, say we had--
back up a few. Say we had given Jordan and David a key of one and two, and now we
added Yowan at the top. React can just see oh, look, what used to be key number one
here, we used to be key number two in this place. We can see that they've actually
just moved to the second and third places here. And so we can actually use that and
just add Yowan here. And so React can do the thing that was actually the most
efficient, and the way it does that is by comparing keys rather than trying to
figure out exactly which value is the most important. And so that's why in this
example here, we passed this element, a long list of elements with names, and React
is complaining, hey, I can't do the most efficient thing because you never told me
what keys there are. And I'm sure that in this list of 1,000 names, maybe there is
one or two that repeat. And so React, when we want to update later down the line,
it doesn't know what it should be doing with those nodes, and so it says, hey, just
as a warning, you should actually pass me some keys. And so if you actually look at
the code over here, we actually assigned keys. And so when we created all those
contacts, we mapped this function called, assign keys. And as you recall from
previous lectures, map passes two values to each of the function invocations. The
first one being whatever the value is in the array, and the second one being the
index. And so we're actually using that index as the key here. And so now in this
example, we can say, hey, React, we have keys for you and we'll actually pass it to
you. And so you can say the key is the contacts key. And so by doing that we pass
React a key for each of the things in the array, and now it can do its magic and
not show us that error. So any questions on passing arrays to elements and why keys
are useful? So let's actually build out this app a little bit more. So right now,
we're showing our users a bunch of contact names, but that's not very helpful for
an app that's trying to tell people their phone numbers. And so let's also display
the phone number. So probably need to wrap this in a view. And this also provide
the contacts phone number. And so now when we map through the contacts, we create
these views, and we still pass that key like we were before, and inside that view
we're passing the contacts name and the contacts phone number. And so now when this
very rerenders we can see a list of names and phone numbers. And so our app is
starting to come into place. So does anybody see an opportunity for making this
code a little bit more readable? Right now every time we're mapping over these
contacts, we're using this element that we're declaring in line. But we can
actually make our code a little bit more readable by rather than having just an
arbitrary few lines creating a element here. We can actually abstract them out into
its own component. And so as we talked about in previous lectures, React allows us
to break our code up into smaller components and allows these components to be
pulled in to other components. And so rather than having these four lines declared
in line here, let's actually create this concept of a row. And so now we have a
stateless functional component, which is just a component that takes a function
that takes props and returns an element. And so right now, we have this thing
called contact dot key, contact dot name, contact dot phone, but instead we should
be looking at the props. And so let's call this props dot key, props dot name, and
props dot phone. And so down here, we can actually just use this real component.
And so we need to pass to the relevant component the prop that it's expecting. And
so that are what? The key, is the contacts key. What else was it expecting? The
name, which is the contact dot name and the phone, which was the contacts phone.
And so basically, we're taking all of the keys of each contact and passing them
down-- the exact values down. So just actually, like we saw earlier, how you can do
dot, dot, dot the object, which will spread out all the key value pairs of object
and pass it to a new object, you can actually also use that in line in React
elements. And so rather than just being very explicit in declaring oh, let's pass
key, which is the contacts key, name, which is the contacts name, and phone, which
is the contact phone, we can actually have a shortcut. We can actually say, for
every single key value pair of the object called contact, pass closing those props.
And so here again, you see that dot, dot, dot notation, which is a very convenient
way of taking a bunch of key value pairs of an object and passing them either to a
new object, as we saw earlier, or to a React component as we see here. And so if we
save and run that, we see a key is not a prop. So one caveat about these keys here
is that you can't-- having it as a prop here in it's own component is not very
helpful for React because React is actually looking at the element not the-- the
element that you map over, not necessarily the element that that element returns,
which is a long winded explanation for just saying you should do this. So we need
to pass the key in to this element, rather than using it as a prop up there.
Actually, which we did, it was just complaining about. So we were in fact, passing
the key because it gets spread out here. But since I was also passing it into the
view up there, the view is saying, hey, I'm not expecting this prop called a key.
And so that should have silenced the warning over here. And so we see nothing
visually has changed in between the two examples. All we did was just abstract out
a smaller component called, row. We could actually take this a step further in
cleaning up our application. So why do we feel the need of declaring this component
called, row inside app.js? We can actually start to break these things apart and
actually have a new file for row, and let's do that together. So I'm going to
create a new file called, row and open it here, and just cut and paste this. And
let's say, import row from dot slash row. Save and quit. It's going to error for
now because we actually haven't finished writing row. And so first, we need to
import a few things, including React. We need to import view, and row, and text,
from React Native. And lastly, we need to actually export row. And so now again,
we're in the same exact place in terms of UI, but our code looks slightly
different. And so why might we have wanted to split this row component away from
this app? So I went to the audience. Why might we consider that a good thing?
Removing this, what's only five lines of code. This component out of this file and
moving it to a new file. What benefits do we have there? AUDIENCE: Use it for
different things. SPEAKER 1: Yeah. We can use it for different things. So
certainly, if you have a bunch of different new files, we can actually pull in a
row to all those files and reuse it, and that way if we wanted to change exactly
what a single row looked like, we wouldn't have to do that in multiple places.
Additionally, it's much more scalable. So imagine a company at maybe Facebook's
size, or Facebook has talked about how they have over 30,000 different components.
Imagine having 30,000 components all defined in a single file. That can get quite
unwieldy. And so by splitting them out into files and splitting those files into
smaller files, we can actually have a bunch of bite size logical pieces, which
compose together to create one more complex piece. And so as we talked about in the
previous lectures, how React allows us to break down a large complex problem into a
bunch of small ones, this is an example of just taking a bite size small problem
and solving it. And then using that bite size small problem in a slightly larger
problem. And so as you'll see in a bunch of lectures, is that rather than solving a
big problem all in one go, it's much easier to swallow off a bunch of small
problems. Great. And now, let's make this look a little bit better. So we have
what's pretty hard to read. And we can just throw some styles on here to make this
look better. And so the way that we do that is by importing StyleSheet, and then
creating styles here. So let's just call this a row and maybe pass in some padding
and call that it. And so now, it's slightly easier to read. So we have this button
that is supposed to toggle the contact list, but it currently isn't doing anything.
Until-- let's actually add that functionality to our app. So we already have the
logic where we have this Boolean flag called, show contacts. We have the logic,
which will flip that flag and so every single time this toggle contacts function is
invoked, it will update the show contacts state to be whatever the previous-- the
opposite of what other previous one. And we already have a button here, which
invokes that. And so let's actually figure out some way of using the ScrollView and
flipping it on and off. So there's a few different ways to do that. We could do, if
the state is telling us to show the contacts then we can return one thing, and if
not, we can return something else. And so here, you might imagine that we can paste
this exactly and if not, we can do that. And that would work perfectly fine. So we
can click toggle contacts, and we'll toggle the contacts. If you click it again, it
disappears. Why might that be slightly un-ideal? What if we started adding some
complexity to that? Maybe added a button for adding contacts. Maybe added a button
for sorting the contacts. Where would you have to update the code? You have to
update here. We also have to update here. And so for every single conditional
render that we do, we'd also have to update that for anything that we want to add.
And so there's actually some sort of shorthand in order to do that. We could say in
here, using JavaScript, we could say, if this dot state dot
show contacts then return this thing, otherwise, return all. And so this is called
a ternary. You may or may not have seen it before. But it's basically saying, given
some expression, if that evaluates to true, return what's after the question mark.
Otherwise, if it returns a falsie value, return whatever is second here. And so
this would be a slightly more legible way of doing exactly what we did before. So
in other words, take the value of this dot state dot show contacts. If it's a
truthy value then return whatever is after the question mark. So the first thing,
which is the ScrollView. Otherwise, return null. And if you null when you pass it
on to a React element, it just renders it nothing. And so this again, does exactly
what we had before. But it turns out there's even a better way to do this. So we
could actually, just do this dot show contacts and this. Because the and operator,
does what? If the first thing is true, it returns whatever's next. If the first
thing is false, it just returns false. And so false and null both just disappear
when you're trying to render those in React. And so this is just saying, hey, if
this is true return this thing. If it's false, just return false. And it's the same
as rendering something null. It's just nonexistent. So this again, does the same
exact thing as we did in the previous two examples, but this in my opinion, is the
most legible. And so if we hop over to the UI we see again, that it does the same
thing. But notice, as I click toggle it takes two or three seconds to render all of
these contacts. And say, we have a very popular person and they actually have
10,000 friends. Now, when we toggle contacts it's-- two, three, four. It's going to
take a few seconds. And so why is it taking so long? So as we saw, ScrollView will
actually render all of its children before appearing, which is somewhat un-ideal if
you have a very long list to render, because even though JavaScript and React are
extremely fast, when you want to take 10,000 elements, map over all of those,
create 10,000 more elements and render all of those, it can take upwards of 20, 30
seconds. And only now has it recently rendered, which can be a problem. Say you
have a very popular person with 10,000 friends. It would be annoying for them if
every single time they want to open this app it takes 20 or 30 seconds to render.
So let's look at a way to making that faster. And if you want to check out the docs
for ScrollView, they're linked in the slides. So there's this thing called a
FlatList. So FlatList is a very performant scrolling view for rendering data. And
what it does is-- it's called virtualized, which it only renders what's needed at
the time that you're viewing it. Or in other words, only the visible rows are
rendered in the first cycle. And so in this example here-- well, it's going to take
a few seconds. That's actually-- in this example here, what happens when you want
to render a FlatList is it will only render these elements. And as you scroll down,
it will say, oh, I need to render more elements and go ahead and render those one
by one. And so as you can imagine, when you want to create that list for the first
time, it only has to do 1, 2, 3, 4, 5, 10 or so elements, which should be blazing
fast At least a couple orders of magnitude faster than rendering 1,000 of them. And
what this means is as you scroll down what used to be at the top might actually
just be recycled. It might be used again in some lower cell, which means that any
rows that leave visibility might be unmounted. So if you're maintaining components
state in each of those, you have to figure out some sort of way to maintain that
outside of the component itself. In a future lecture, we'll talk about some data
handling libraries that allow you to do that. But for now, just avoid using any
component to state in these rows. So how do you use this? So we have to pass a
couple things. We have to pass the data. And so as you can imagine, if we have some
sort of list that's the rendering data, it needs to have the data. And we also need
to tell it how do we render each of these data points. And so we pass an array of
that data and a renderItem function. And so this renderItem function, it's a
function that takes an item and returns an element, similar to the row component
that we declared earlier. And so let's go ahead and use this. So here, we have a
ScrollView, but let's actually call this a FlatView instead. And so unlike the
ScrollView, where the ScrollView, we actually declare all the rows as children, for
the FlatView we're actually going to pass props. And FlatView is smart enough to
know, hey, given these props, I know how to render all of my children. So I can go
ahead and do that in a very optimized manner. And so we can actually just get rid
of this here. And let's have a FlatView. We need to pass it data, and so the data
are going to be the contacts. And we also need to pass it this thing called,
renderItem. And renderItem takes some sort of object and returns whatever we want
to render for that item. And so for each item, we want to render a row. And what
are we passing to the row? Well, we want to object spread something, and so let's
just do object dot item. And so I only know this because I read the docs, but the
object that's passed to the renderItem function, actually has this thing called a
dot, called an item as part of the object. And so I go ahead and use that here. And
so we've passed it renderItem and we've passed it some data. And I believe that is
all that we need to pass it. And so let's see what happens. That's actually-- real
quickly. Sandy, will you check this? Let's actually, just declare this outside the
function and see if I made a typo. FlatList, ah. And I also imported FlatView
instead of FlatList. All right. Now, we see that it goes ahead and renders almost
instantly. And so as we see again, pretty instantly. And so let's actually scale
this up, and do again that example with 10,000 contacts. And again, we see that it
is no slower in rendering those 10,000. And I put that into air quotes because
really, it's only rendering what's on the screen now. And as you scroll down, it
actually just will render the things as we get to them. So one downside or upside,
depending on how you look at it, of FlatList is that it only updates if props or
changed. And that's actually an optimization done by the React team so it doesn't
necessarily rerender. And so let's actually add a feature to our application here.
And so right now, say I'm looking for a friend named Aaron. There is really no way
that we've organized this so that I can find Aaron easily. And so one thing that we
can do is we can actually, sort this alphabetically. So if I want to find a friend
named Aaron, it's very easy because he's at the top. His name starts with A-A. And
so let's add this feature to the app. And so in order to do that, we need to have
some sort of button that's going to sort things, and we're going to have to
actually sort things as we go. So let's define a function called, sort. And what it
does is it will take the list of contacts and go ahead and sort it. So let's do,
this dot setState and take the contacts. Take the previous states contacts and
invoke this thing called, sort. And so as part of the array prototype, all of
arrays have this method called, sort. And sort will take a function that compares
two values and just will sort them in increasing order. And so for things like
strings or things like numbers, it's very easy to compare those because JavaScript
knows hey, given two numbers, it knows to use the greater than or the less than or
the equals to compare them, and same thing with strings. But for objects, it's non-
obvious to do that. And so that's actually what this compare names function here,
is for. It's for us to compare these two contacts while we alphabetized them. And
so let's actually import that into this function. So we want to import contacts,
the default export, and also this thing called, compare names from contacts. And
let's go ahead and sort that list here. And so we pass them to sort that function.
And so when we invoke this thing called, sort, what we do is we take whatever the
previous state contacts were and we sort them. Obviously, we need in state our
contacts. And lastly, we want to have a button that will sort things. And then
rather than passing contacts here, let's doe this dot state dot contacts. So since
we're so worried about performance right now, there's actually one big performance
issue that we have right now. So when we declare a renderItem, what we're doing is
we're passing it a function that we're creating right now. And so every single time
this component rerenders, a new function is created. And so let's actually move
that into the class. That way we can just pass that reference. And so let's say,
renderItem is this. And here we can just pass this dot renderItem. And so now, we
see that we can toggle the contacts, and we see that we can sort. But when I click
sort, nothing actually happens, which is a very strange bug because if we toggle
again, now we see that everything is sorted. And since I was looking for my friend
named Aaron, fortunately, I have a lot of friends named Aaron and they all are at
the very top. Let's look at that again. So I can see in my contacts. They're all
out of order. I click sort, which is supposed to sort them, but nothing actually
changes. But if I then toggle on and off, all of a sudden everything is sorted.
Very interesting. And so we talked about how FlatList, it only updates if props are
changed. And are we actually changing any props? So we're passing down as contacts
a sorted list of the previous contacts, but is that actually changing anything? So
if you look at the documentation on array dot prototype dot sort, it actually does
this in the same
array. It actually mutates that array such that all of its values are sorted. But
it doesn't actually create a new array itself. And if you remember back in previous
lectures, how do we compare objects? They're actually just stored by reference,
right? And so since this is the exact same array, when you pass it down to the
child down here, the reference doesn't actually change. And so as we saw, FlatList
doesn't update if it's props don't change. And so since we're sorting this in line,
the array itself doesn't actually change. And so if we want to do this correctly,
we actually need to use what's called immutability. And so immutability is this
concept by which, if we're given some sort of object for-- or if we're giving some
sort of value, that value is guaranteed to not be mutated. And if we want to change
that value, what we have to do is we actually have to create a new value that's
very similar, but we change what we wanted to change there. And so in this example,
rather than using the same array and sorting within that array, we actually want to
create a new array. And so again, there's a quick way to do this by using that dot,
dot, dot notation. So if we create a new array literal, so just two brackets,
that's creating a new array. So that took care of the create new array part. And if
we do dot, dot, dot preState dot contacts, that says, all right for every single
value in preState dot contacts, clone that into a new array. And so to be very
explicit, for each of the values and contacts, those objects have not changed at
all. They're still the exact same objects, exact same object references, but
they're put in a brand new array. And so when we pass this new array down, it's a
brand new array and it will rerender. And of course, if we do dot sort on this new
array, since that FlatList hasn't seen this new array before, it will go ahead and
rerender. So now, if we save this, show our contacts and sort, it goes ahead and
works. So any question on FlatList or virtualized or scrolling list that we've seen
thus far? Yeah? AUDIENCE: [INAUDIBLE] SPEAKER 1: Can you repeat? Can you repeat the
question? I missed the last part. AUDIENCE: [INAUDIBLE] SPEAKER 1: Right. So the
question was, for renderItem. It takes as an argument the object. And what exactly
is this object? Well, we can actually just look at the docs and it tells us. So in
the docs if we look for a renderItem, it tells us exactly what has passed as
arguments to renderItem. And so as you see here, renderItem is invoked with the
item, which is an object, as well as a few different things like index, separators,
which we don't care about. We really only care about the item. And so since I read
the doc page, I know that one of the keys that is passed to renderItem in the
object is called, item. Does that answer your question? So the reason that I have
object here, an object to item, is because I know that the object passed to
renderItem has a key called, item, which refers to the item in that data. AUDIENCE:
[INAUDIBLE] SPEAKER 1: So FlatList takes care of passing the object for you and
creating the object and doing all of that. Really, all we care about is the fact
that we have the item passed here. And actually, there's shorthand for that as
well. Rather than passing this object, we really only care about the item. So just
like their shorthand for a lot of things, so the analogous-- so when we wanted to
create an object, if we have a variable called, item, and we want to create an
object with a key called, item where the value is item, all we had to do is this.
You can actually do that in reverse. Say we're past an object with a bunch of keys
and we only care about one called, item. We can actually use the syntax, which will
create a new variable called, item, and extract that key for you. So another
shorthand that we see is rather than being passed an object and only using object
dot item here, we can actually-- what's called destructure that object. Pull that
item and use that there. And again, the only reason that I know that this key
called, item, exists is because the documentation for FlatList told me hey, we're
going to create this object for you, pass down this item, and you just can use the
item there. And so that's all abstracted away from us. We don't really care about
anything else. We just care that the item that's passed down is called, item in
this object. Yeah? AUDIENCE: [INAUDIBLE] SPEAKER 1: So the question is-- so I'll
just answer. So the data is in an array of arbitrary things and each item that is
rendered takes one of those values, puts it in a key called, item, and passes it to
whatever the renderItem function is. And so we defined it such that it passes-- it
takes an object with an item key, and passes that into our row component. AUDIENCE:
[INAUDIBLE] SPEAKER 1: So what is item here, is the question. And so item here is
an object in the shape of name and phone, where name is of type string and phone is
also of type string. And I know this because I know that each of the data points
inside of data is of the same shape. So if we open-- so up here in contacts.js,
when we created that array, it's an array of contacts where each contact is a name
and a phone number. And so that array is passed into here when we import it in. And
then that array is the same data that we're passing to FlatList. And so this dot
state dot contacts is what we exported from here, which is an array of names and
phone numbers. And so what FlatList is doing for is it's automatically taking all
of that data. So the data is a bunch of objects of the shape, and it's lazily, and
when I say lazily, it means only when it's in view, rendering each row or each
item. And so for each item it needs to know exactly how to render it. And so what
we're passing is a function called, renderItem where the renderItem takes a bunch
of configuration, one of which is the item itself, because it needs that
information in order to know what to render, and then passes that into whatever we
want. And so we declared up here, that when we want to render an item, we take
whatever information is, so the value of the array itself, and just pass those into
the component that we called row. Does that makes sense? AUDIENCE: [INAUDIBLE]
SPEAKER 1: Here? AUDIENCE: Yeah. SPEAKER 1: That's just that special notation. So
we can ignore that. So that's the same as this, which is the same as this. So that
was just a bunch of shorthand for this. So we know that we're passing an object. We
know that the item that we pulled out of data is object to item. And we know that
item has two keys, name and phone. And so we can just say name is object to item
dot name and phone is object to item dot phone. And if you're reading source code
from any libraries that you see, most people will use all of JavaScript shorthand,
which include pulling out item automatically by using less shorthand there, and
using all the key value pairs automatically by doing that dot, dot, dot
destructuring notation. But this effectively does the same thing. Does that make
sense? Great. Let's take a five minute break and then we'll go ahead and look at
this and other lists after the break. Hello, and welcome back. So before the break
we were talking about the lists and the list components React Native gives us. I
mean, we showed an example for FlatList, and one question that came up in Slack,
was how come the warning for keys was not popping up even though we were not being
explicit about the keys in the example here. And so one thing I left out when I was
talking about the shape of items here was that key exists, which was number. And if
you look at the FlatList docs, it actually automatically extracts the keys for you.
And so if you have a key value in the objects that you're passing in that data
array, then it will use those for the keys. And if you want to use something other
than a key property, then you can pass this thing called a key extractor, which is
a function to FlatList. But for our example, since each item had a key, then it
worked and automatically extracted that key for us. So a great question from Slack.
So another scrolling component is actually called a SectionList. And so if you open
up your actual contacts on a phone, it will actually give you sections with section
headers. And so this component is exactly like a FlatList, but we have additional
support that will automatically use those section headers for us. And so instead of
a data prop, we actually just define sections. What do those sections look like?
Well, each section has its own data array. So unlike in FlatList where we had array
called data, we now have an array called sections where each section is an object
with its own data array. And each section has the opportunity to override the
render item function with their own custom renderer. Say if you wanted to have
different colors or different backgrounds for each section, you could do that by
overriding the render item function. And for section headers we just pass a
separate renderer. So just like we defined a renderer for the items, we just also
define a renderer for section headers. And so let's take a look at what that looks
like. So if we replace FlatList with SectionList and we passed-- rather than data,
we pass sections where sections is actually an array of sections. In this example,
lets just hard code those sections where one of the data is, this dot state dot
contacts. And let's say the title or something. We can call this whatever we want.
Let's just call it A. So we're passing it a render item, which tells it how to
render a particular item. We're passing the sections, which each section has its
own data. I mean, each section has its own title. We're not telling the section
list exactly how to render those sections. And let's go ahead and do that. So let's
do render section header, it's
called. Let's do render section header. So now, we have to go ahead and define
that. And let me check my notes to see exactly what that object looks like. So just
like we have an object here, we're passing an object down. And just like this
object in the renderItem, has this thing called an item. This thing called
intersection header has a section. So let's just pass it text and do ob dot section
dot title. And again, the only reason that I know this object dot section key
exists is because I looked up the docs and wrote it down. And so I know-- so just
like this object has this thing called object dot item, which refers to the item
itself in the data, this object has object dot section, which refers to the section
that we're passing down here. So refer to this object here. And so since the object
has a key called, title, we can go ahead and use it in here. And so now, that is
more or less complete for SectionList. We give it a way to render each item. We
give it a way to render each header and we tell it what the sections are. And so in
this example, we have a single section that's an object with a title called A, and
data being all of our contacts. And so if we go ahead and show that-- save it. And
there is a syntax error somewhere. Here. If you go ahead and run that, we can see
that we have a section header here. Just the A, and then following it are all of
our contacts. And again, this is another one of those virtualized lists where it
lazy loads. And so if we toggle it, it immediately loads even though there are
10,000 of them. Just because it's only again, rendering what we see on the screen.
And as you see here, that A is that section title. And so let's actually improve
this a bit. And so right now, we have hard-coded the fact that we have a section
called A with all of our friends down here. But what if we actually wrote a
function that figured out people's appropriate sections. And so everybody whose
name starts with an A should be in the A section. Everybody whose name starts with
a B should be in the B section, and so on. And so let's go ahead and write a
function that does that. So how might we do that? So first, let's clean up our code
a little bit. Right now, we have this section list down here, but this is another
example of a time where we can abstract another component out of this. And so let's
create this thing called, our contacts list. And into that, let's just cut and
paste this section list. Let's just save this for now, so we have some room. And so
here, let's create this thing called, a contacts list, which is a stateless
functional component, so it takes some props, and it will return this. But before
that, let's do some things. Actually, first let's complete this example. So first
we need to import React, and we need to import SectionList. And lastly, we need to
export this because without exporting it, we can't import it into our main
application. And so let's call this, props dot render item, props dot render
section header, and props dot contacts. And so now, we have three props that are
passing down, so it might start to get a little bit difficult to keep track of all
these props. Does anybody remember something that we discussed in a previous
lecture, which will actually self document all of our props for us? There's that
package called PropTypes. And so if we import PropTypes from PropTypes, this is
that package allows us to self document things. So if we forget to pass down a prop
or we don't remember what a prop should look like, like what data type is it, we
can actually use PropTypes to one, check at runtime are we passing the correct
props, and two, to just document for us so that when we open a new file, we know,
oh, we should be passing this component, these particular props. So again, the way
to do that is by adding this key to contacts list called PropTypes and defining an
object with those key value pairs. And so we're expecting something called a
renderItem, which should be a function. We're passing down render section header,
which again should be a function. And we're passing down some contacts, which is an
array. And so now React will tell us if we're passing down the wrong props. And so
let's go ahead and use this contacts list in our application. So here we want to
import prop ContactsList. ContactsList. And down here, let's go ahead and use that.
And what props are we passing down? We're passing down to render section header and
renderItem. We're passing down render section header. And finally, we're passing
down contacts. And just for fun, let's actually pass down an object for that. And
so we'll see if we pass down an object, one, everything is not going to work, and
two, it's telling us, hey, failed prop type. We expected contacts to have type
object. Or we passed contacts of type object when we're actually expecting an
array. And so again, prop types as we showed last lecture, is just a way for us to
catch bugs. So if we're passing down something that we think is of one type and is
actually of a different type, it will catch those bugs for us and tell us, hey,
we're expecting array here. And so for contact's, we should actually be passing
down the contacts. And so now, we are back to where we were before. There's one
thing that I think is a little bit strange about this example. So does the
application really care what renderItem is? Does the application really care what
render section is? In a way, yes, but where should that really be defined? What
component actually really cares about renderItem in render section header? It
really is the ContactsList, right? Because the application doesn't really have
anything to do with the logic in app.js. And same with render section header. The
fact that render section header is just some text doesn't have anything to do with
the other logic it has on js. And so what might be a better place to implement this
logic? AUDIENCE: In the other file. SPEAKER 1: Yeah, in the file called,
ContactsList. And why might we want to do that? So imagine down the line we're
saying-- so imagine down the line we have a very, very complex app with contacts
and everything. And say we were saying, oh, this is a cool contacts list, but I
think the rows a little bit ugly. Let me go change that. And say it wasn't you, say
it was a friend who is helping you on this project. Where are they going to turn to
for changing that? They're probably going to look at the component that renders it,
right? And so by having the renderItem, which is arguably something that the
ContactsList is solely responsible for. Having that logic inapt on js is going to
lead some problems down the road, for one, maintainability, two, readability, and
three, scalability. And so all of this just goes down to the fact that renderItem
is really something that contacts cares about and not app.js. And so how might we
go about solving that problem? Well, we can just move that to the other file. So
let's take those, cut and paste that here. So what we did is we removed those two
functions. We can remove the render section header here. We can remove rendorItem
here. And now, all we're doing is we're passing ContactsList the contacts, which
makes sense, right? What should ContactsList need to render? Just a list of
contacts, and that makes sense. So it's API is saying, hey, I can render
ContactsList, all you have to do is pass me the contacts. And so by removing the
logic that's not unique or not necessarily cared about inside of app.js, outside of
app.js, it now makes more sense in like a mental model. So everything that's needed
for ContactsList to render should be implemented in ContactsList. And so now, let's
finish this. So now, we just created those two functions. So we have a function
called, a renderItem, and it is the same as it is before. It's an object that
returns a row. And of course, we had to import row. And then we have a cons called
render section header, which is the same as it was before. It's an object, which
returned some text. And of course, we had to import in text. And so now, we can
just go pass that in there rather than looking for its props. And now, if we save
that, again, we're in the same place in terms of UI, but our code is much, much
neater. If you look at app.js, it's returning something very simple. A couple of
buttons, which are needed, and a ContactsList, and we're passing the contacts. And
so again, now this bite size piece of application just-- this layer here, is very
simple. We have a view with a couple of buttons. We take care of those buttons
logic in here. And then we have a separate component called, ContactsList, and we
pass the list of contacts. And so this is a very simple way of stating our app. And
if we want to get into the implementation details of ContactsList, we can just look
at the ContactsList component. And in here, we have the logic necessary for
ContactsList. We're defining what it looks like to render a single item. We're also
telling the SectionList exactly how we should be rendering a section header. And of
course, we're just looking to our props for the contacts themselves. But then, what
the heck is a row? And so again, that's another bite size small piece of our
application. So if you want to look at the exact way a row is implemented, then you
can just look at the row file. And here, is another simple problem that we've
solved. So a row is just a view that tells us some name and a phone number. And of
course, styles it a little bit by adding some padding so everything's not squished
together. And so what is turning into a more complex app is actually, just a few
different simple files. And so as you work on your next project or personal
projects in the future, you can start to use these paradigms where you have a big
complex problem, and break it down into smaller components such that each one is
very maintainable.
Each one is very readable. And so if you want friends to work on that with you,
it's very easy to tell them oh, if you want to change this part of the application,
just look for that particular file. And so now, let's actually tackle that hard
logical problem where we have an array of contacts and we want to split that into a
bunch of sections where each section has-- the section header is defined by the
first name of the contacts. So how might we do that? Well, first we're going to
have some logic that we're going to want to do before we return the section list.
As a first, we might want to say, take props dot contacts and split that up into
that-- the shape where we have an array of objects separated where the title is
again, the first letter of every single contact in its data. Can anybody think of a
good algorithm to do that? So the way I would implement it myself, is I would go
through the array, turn that into an object where the keys in the object are the
first letter of the values in that. And then go from that shape, whereas an object,
where the keys are letters and the value is an array of all of the contacts with
that letter, and turn that into this shape. And so let's go ahead and implement
that algorithm. And I'll go a little bit quickly for the sake of time. Let's do
contacts by letter. What that does, is it takes props dot contacts and reduces it,
where the reduction is taking the objects, which is the objects that we eventually
want to get to, where it's the keys are the letters and the values are an array of
all those contacts, and it takes the next contact. And we want to of course, start
with an empty object. And so for each contact, we want to grab it's first letter.
So we can say, take contact, the very first letter in the string and uppercase it.
And of course, we want contact dot name. So contact dot name. So grab its name,
look at it's first letter and uppercase it. So now, we've extracted the first
letter of each contact. And then what? We want to add that to that object. So we
want to return some sort of object where it maintains all the previous keys of
object and appends this particular contact to the key, which matches it's first
letter. So that's a little bit of work to do, and we can actually do that all in
one line. So what have we learned today, which is a quick way to clone all of the
old keys of an object? We can use that object spread. And so now, all this is doing
is just returning the same exact object, but in a new immutable object. But let's
actually add this contact. So you want the key to be first letter. And so you can
wrap it in brackets and just like, this will evaluate zero to become a string. This
will evaluate this to become the key. And what do we want the value to be? Well,
it's going to be an array. And the array is going to be all of the keys that used
to be in that object. And so now, we've again-- this actually returns pretty much
the same object as before. So it's cloning all of the keys in object, except it's
overriding the one where the key is the first letter that we extracted from here.
And what are we setting to be that as value? Well, we're setting a new array and
we're setting that array equal to basically, everything that was already that
objects-- where the key was the first letter. And so this is a complicated, but
basically, it hasn't done anything yet. We've just cloned that object. And so how
are we going to actually add that contact to this array? Well, just like that.
Still with me? So now, we're returning this object and we're building it up as we
go. And so we want to say retain all of the previous keys. Just say we have A
through Z already. Make sure we don't lose those, so go ahead and clone that
object. And override whatever key is equal to that first letter. And so the first
letter again, is just upper cased the first letter of each contact. And so we
override it with a new array where that new array is the old array, but add that
contact. Yeah? AUDIENCE: [INAUDIBLE] SPEAKER 1: Great question. No. So the question
was if objects with the key first letter is undefined-- so if this is undefined. So
say, this is the very first iteration, it's an empty object and so object A does
not exist. Will this still work? No. So we have to actually handle that corner case
still, but great catch. And so let's actually handle that corner case. So what
happens if it's undefined? So now, we'll say oh, if it's undefined, just consider
it to be an empty array. And so when you spread the empty array then that's nothing
and then contact, and so you're left with an array with the contact in it. So I'm
going to wave my hand at it for now since we're running a little short on time, but
if you have any questions about this function, please feel free to slacker email me
and I will talk everybody through it. And so now, let's go from the contacts by
letter to something of the shape, title, and data. And so how might we do that?
Well, we can actually just map over those keys and create that. And so I'm going to
go a little fast in the sake of time. So object dot keys takes all of the keys of
an object and in array. So now, this here, is an array where the keys are the keys
of whatever the contacts by letters are. It's going to be something like A, B, C,
D, E, F, G, but leaving out things like X If we have no friends whose name begin
with X. Let's just sort it just in case it's not sorted already. So say something
like, A, C, B. We want that to be A, B, C. So we can go ahead and sort it. And then
let's run a map over it. So for each letter, what do we want to do? Well, for each
letter, we want the section title to be that letter. And so we can do the title
here is the letter. And the data, we actually want to be the data that we created
up here. And so how might we do that? Well, we can just get the contacts by letter
and grab its key or that keys letter. So again, going a little bit fast because
we're short on time, but we're grabbing all of the keys of contacts by letter. So
that's going to look something like the alphabet. Sort it to make sure it's in the
correct order. Then for each of the letters, we turn that letter into an object
where the object matches the shape. Where the title is the letter, and so it's
going to be something like title A, title B, title C. And the data is actually the
data that we created up here. And so when we do contacts by letter, we pass it the
letter, it just grabs that array. And then we can pass sections down here. And let
me see. So in theory, now we have sections, which looks like an array where for
each array we have an object where the letter is the letter of the first letter of
every single contact in it's data array. And the data array of course, is all of
those contacts. And so now, the moment of truth. When we toggle the contacts, we
see A followed by a bunch of people whose first name begins with an A. And since
there are 1,000 of them, there might be a lot of these. And this actually simplify
this. Let's make this 100. So now, we see A, where we see a bunch of people whose
name begin with A. We see B, for Benjamin here, and C, and so on. Each one with a
section header that corresponds to the first letter of all those people. And if we
wanted to style that, we could do so by just changing that render section header
function. And so now, we have something that looks almost exactly like the contacts
list in your phone. But there is one piece missing. What happens if you make a new
friend? And so let's do that. Let's have-- or add some sort of way to add new
friends to our list. And so what sort of things do we need to need in order to do
that? We should probably have some sort of form where you grab somebody's name and
grab somebody's phone number, and then it should add that to your list. So let's go
ahead and implement that. So that requires something called a user input. And so
something that is often somewhat difficult to handle. And so there's a bit of a
debate that goes on in the React community, more so React Web and less so React
Native, should we use controlled or uncontrolled components and what do these
things mean? Well, it's where exactly is the source of truth for the value of an
input. And so if you imagine just in HTML form, you have an input where you can
type into. That input now how has a value, and who's keeping track of that value?
And so controlled versus uncontrolled component is actually that debate. So in a
controlled component to react to controls, what's in that value, whereas in an
uncontrolled component, it's actually controlled by the Dom itself. And so if
you're writing some static HTML and you have something like an input tag, when you
type into it, it retains the value that you type. That's because the Dom tracks
exactly what you're typing. But in a controlled component, React is the one that
controls that. And so if you imagine now, in the React world if you have an input,
every single time you change that, React is going to have a variable that tracks
that. And then what determines the value of that input? Well, it's whatever value
React says that input should have, and that should correspond with whatever the
value of the variable that React is tracking is. And so this goes back into the
whole like, who keeps track of the Dom debate? And so in React, you actually have
no choice. You have to use the React virtual Dom, which will then write to the
actual Dom. And the same thing here. So who keeps track of the value of the user
input? And so in a controlled environment, React does, you do as the person writing
React. You say, every time this input changes I'm going to update a value that I'm
keeping track of. And what dictates what's inside that value, well, it's what I say
it is. And obviously, you just set that to whatever value you're keeping track of.
And so we can see that example in a moment.
React recommends always using controlled components. That way you have those
values as JavaScript variables. That way if you want to submit a form or do some
validation, you can do that all in JavaScript because you're keeping track of those
variables in React and presumably in the state. I mean, how do we actually create
those variables? Well, you pass a prop called unchanged text to a text input, and
you pass a value that determines what is the value of that input. And if you want
to see other props that you can pass to text input, you can look at the doc page
there, but let's do an example with those. And so in order to add contacts, we
agreed that we needed some sort of way, some sort of page to do so. And so let's go
ahead and write some page. So let's have this thing called, add contact form. And
let's have this be a component. We're going to need a couple of components like
view, which we've seen many times before, and text input, which is what we'll be
looking at today, and we're going to create this class. So this class is going to
have in it a form where you can dictate what your user is. So in the render
function, we're going to want to return a view with a couple of text inputs. And
then probably we're going to what some button to submit. And so now, we have the
shell of what is going to be the add content form. And so just like in web or in
any other project, you have a form that has a couple of inputs where each input
refers to some value in your contacts. In the future, this is going to be the name.
In the future this is going to be the phone number. And of course, some way to add
that user to submit it. And so we have a button where whereby we can add that
contact. And so we can go ahead and expect that somebody already has implemented
that add contact function, and so we can state that we're expecting a prop called
add contact. And so when we submit this, we're going to just invoke that. But how
are we going to keep track of the text inputs? Those values? And so as you see on
the slide, they expect two props. They expect a value, so something that determines
what their value is. And how do you update that value? So a function called,
unchanged text. And so let's actually initialize a state. And I'll again, use that
shorthand for class properties where we're going to have the name be blank and the
phone be blank. And so what dictates the value of this one? Well, it's going to be
the value in the state. And same with the phone down here. And now, let's go ahead
and get this form hooked up in our app. And I'm going to go a little bit fast for
the sake of time. So import that. We're going to have in state, we'll say, show
form. We want to have some sort of way to toggle that. So let's call this, toggle
form. And we'll just say, show form is opposite of show form. And now, let's have
another button. Let's get rid of the sort button and instead call it add contact.
So now we have another Boolean flag, which is updated by a button, which toggles
the form. And let's do this a quick and easy way for navigation. So if we should be
showing the form, then just show the form. Otherwise, return the default. And so
now, we have this been called add contact, and when you click it, we see this other
page, which we've partially implemented, which right now, only has this add contact
field. So now, let's go ahead and finish up that form. First, let's add some basic
styling. Let's give the input some padding, a border, and now they should be a
little bit more visible. And so now, we should be able to see the inputs up there.
Again, there's one that's way up there, so let's just add some quick style. So now,
we see those two inputs there. And if I type into them nothing is happening. Why is
that? Well, because right now, React is a source of truth for the values of these
text inputs. And what is the value, is this dot state doe name. And what is the
value of this variable? Well, it's a blank string. When does it update? Well, it
never does, which is why no matter how many times they bash on the keyboard,
nothing is updating in that text input. And so how now might we start to update
this source of truth? Well, we need to tell it how to, so we need to create this
function called update or let's call it handle name change, which takes a new name
and it will just do this dot set state the name. And same thing with the phone
number change. So now, we have a couple of handlers. We have handle name change,
which takes a name and just updates in the state. We have a phone, which just takes
the phone number and updates it in the state. And now, all we have to do is tell
those text inputs hey, how do we update that value in the state? Well, on change
text, is this dot handle name change. And same thing down here. We have the value
state dot phone, and the way to update the value is by calling this unchanged text,
which is this dot handle dot phone change. And so now, when you start to do this,
it actually updates accordingly. Lastly, for the phone number, doesn't really make
sense for it to just be all letters, and so another way, another prop that we can
pass down is this thing called, keyboard type. And we can say numeric. And if you
want to see what other keyboard types there are, you can go ahead and look at the
doc pages here. But now, when we click the phone number, we see this. And so now we
have a way to handle user input. And in future lectures, we'll talk about how to
maybe validate that and how to handle stuff like that. And so on that note, I will
close the lecture.

You might also like