[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.