Hey guys in this lesson we're going to level up our knowledge around React components, and to do that
we're going to learn about something called Props. So head over to the starting CodeSandbox and go ahead
and fork it. And once you have it
feel free to download it to use in your local environment or follow along with me in CodeSandbox.
So here I've got a really simple Contacts app. So I've got three people that I supposedly know their names,
a picture of them that I found on the Internet, some fake phone numbers and fake emails. As you can see
if we look inside our index.js, this is pretty repetitive and it's also very long, and this is
one of the perfect use cases for React components because we have these repetitive elements that is
cluttering up our code making it very long and very complex, unnecessarily.
So let's go ahead and extract each of these contacts as a brand new component.
I'm going to create it just inside my index.js so you can see quite easily
both the component and the rendering side by side.
And I'm going to call this component a new Card like a contact Card, and it's going to return
each of these contact items.
So I'm just going to cut Beyonce out of there and I'm going to insert her into a div.
So now this h2 image and two paragraph elements are now being returned from my Card() function.
Now I'm actually just going to go ahead and take out these other guys from my render() function, and I'm going to
keep my website as simple as I can
so you can see easily what's happening.
So instead of having all of those divs, I can now create maybe three Cards instead,
right?
So I've got three Cards like so, and once it reloads you can see that yes, I do have three Cards which
all have a h2, an image, and two paragraphs but they're all of Beyonce.
So that's not what I want,
instead, I want to have different pieces of information in each of these reusable Card components. With
the knowledge that we've gotten so far,
it's actually very difficult to make these components reusable. And it's because we haven't got any ability
to send these Card components some custom data so that each of the cards gets rendered differently.
Now let's think about how this problem is solved in plain old HTML.
So if we had over to the index.html, and let's just go ahead and delete all of our Cards from here, so
that we clear up our screen. And right below my "root" div where we know our React components are going
to be rendered,
I'm going to go ahead and create just a plain HTML element. And remember that when you're creating a React
app you're not limited to just using React.
You can just insert it any way you like using a div with a particular id. And the rest of the file
can still be worked like a regular JavaScript or HTML file.
So that means if you have an existing website, it's really easy to just insert a "root" div and then start
adding React code into that particular position.
So I'm going to create a plain HTML element which is going to be an input element, and I'm going to
make it self-closing as well.
And you can see that it shows up in here as a little text box. Now this input element has attributes,
right? Attributes which I can set with custom values.
For example, I could change the id of this input,
let's call it fName,
so like, a field to input your first name, and then I can also give it a placeholder.
So I could say that, "Enter your first name."
And once we refresh you can see the place holder goes up in gray.
And I can even set the value even before the users had a chance to interact with it.
So let's just say I'm going to put my own name in there, and you can see that I've now got an input field
with a value that's already pre-existing inside.
And if I delete it and make it empty, then you'll get to see my placeholder text.
So this is kind of a way for us to pass custom pieces information via these attributes to a particular
HTML element,
right?
And if we go ahead and take a look at this app in a separate tab and I open up my Chrome Developer Tools,
then I can actually access this element by just grabbing hold of document.getElementById and we
called it fName.
So this should actually get hold of this particular input element.
And I'm going to save it into a variable. I'll just call it input and then hit Enter.
So now I've got this input value stored, then I can actually access all of its values.
I can say, input.placeholder to print out the value of the placeholder attribute.
I can also say something like input.value to print out the current value of the inputs, and I can even
change this, right?
So effectively, we're using these attributes from our HTML elements to send and custom pieces of data to
that particular element.
And over here when we tap into that element using getElementById and we have a reference to it, then
you can see it's almost like as if we have the input as an object and we're accessing each of its properties
like .placeholder or .value.
Now these attributes are predetermined and there are lists of them in the MDN docs, but we can't
go beyond what is actually here.
We can't define our own custom attribute,
right?
If I created something called, I don't know, just Angela and I tried to give it a value,
and I go into my React app and I try to tap into input.angela, that doesn't actually work. But if
you think about your React components almost as a custom HTML element then we can define these attributes.
And in the React component world, those attributes are called properties, and you'll usually hear them
referred to as Props. Let's say that I decided to create a new Card component from my Card function(). And
what happens behind the scenes is it's almost like I'm calling this function Card, and it returns a custom
HTML element based on my instructions. But when we take a look at these custom React components, we can
pass properties using very similar syntax to what you saw over here.
So if I go ahead and cut this input out of my index.html and I paste it down here just below my
Card, you can see that with our Card component, we can do exactly the same thing.
So I can pass my Card a value, for example, name, and I can set that equal to, "Beyonce", for example, and
when this Card component gets created, it will have a property called, name, that's set to equal to Beyonce
And we can get hold of it by adding a name to the inputs to access those things that are sent over.
And it's customary to call these props. For example, inside this function, I can console log the value of
props and if I hit Save and we take a look in our console, you can see that it receives an object,
and currently, the object just has one property with a value set to Beyonce.
So what this means is that in fact, we can actually completely remove all of these hard-coded parts of
our React Components and instead rely on inserting the values of these props.
So I could say props.name which I know to be the property that I sent over and it's equal to
Beyonce.
And now what I can do is I can, for example, copy the src and add that as a property. So I'll create
a new property called img and set it to equal the URL of that image. I will create a property called
tel for telephone, and I'll set it equal to that number. And I'll also create a property called
email which I'll set equal to that made up email.
So now inside our Card component, I can access that object called props which has all of these properties
passed in as an object and I can tap into each of these properties as long as I know what they are called.
So the src was stored inside a property called img, so I can write props.img,
but remember that this is Javascript, and we're inside an HTML element inside our JSX file,
so be sure to enclose it in a set of curly braces if you want it to be interpreted as Javascript.
Next I've got my props.tel
and my props.email.
So I've ended up with exactly the same card as before
but the crucial difference is that this Card no longer contains any Beyonce specific information.
And what I can do now is I can create as many of these Cards as I need with different pieces of information.
And I want to pose this as a challenge to you, go ahead and try to create another Card with an imaginary
contact if you wish, or a real contact even, and see if you can add a second Card to our website.
That second Card should appear just below Beyonce but it should have a different name, a different
image, email, and phone number. Pause the video now and see if you can successfully reuse our custom Card
component.
All right.
So I'm going to create another Card and this is a self-closing tag with no children.
And I'm going to add some properties.
And remember that because inside our Card() function it's looking for these properties: name, image,
tel, email, we have to keep it consistent in between the Cards.
So let's say that name is Jack Bauer,
img is equal to some sort of image that I find online,
and then we've got tel which will set equal to some random numbers, and email we'll set equal to...
So perfect,
we've now got two cards with completely different information and we're able to reuse this Card component
with all of its structure as well as styling if you wish.
So these could actually have class names associated with them or inline styling if you wish,
but all we need to do here in our render() function is to provide the customized pieces of data and everything
that stays the same lives inside this Card component.
So now as you can imagine, if you wanted a contact list with many, many people, you can simply just reuse
your Card component.
And this brings us to a good point.
If you remember previously, I said that if you had a style, let's say...let's just give it a className,
let's just call it my-style, and all it does is it changes the text color to red, and we save that CSS file,
and we go back into our React code,
you can see that if I was to add that class to my div for example,
so I'll say className = "my-style" and I hit Save, and refresh my website,
all the text inside that div has been changed to red, right? But I can't do the same thing inside my custom
Card component.
I can't for example add the className attribute and then apply my-style. Even if I refresh a million
times
it's still not going to work.
And this is because inside our custom components, it sees each of these as a custom property.
So it thinks that you're making up a name called className and you would like to access it inside this
Card component under the props object, instead of seeing it as an HTML attribute.
So whenever you're using HTML predetermined attributes, they always have to go into the HTML elements which
are highlighted in different color and also they're in lower case.
So this is the reason why we can't do that. But inside our custom components, we can create any name we
want and associate it with any value we need.
So it's almost like we're calling this Card() function and passing over an object through the input called
props.
And then inside the function, we use those inputs to customize this HTML element and then we return
it and output it into our DOM to be seen on the website. In summary with HTML attributes,
we have the HTML tag and then we have a space and we get to use these predetermined fixed name attributes
such as id or placeholder or value.
And these of course depend on the actual element that we're using.
And when we use these attributes, we can pass in some custom data. And that data can then be accessed
on the element by tapping into say the .id or .placeholder or .value properties.
Now when it comes to React, what we have is a very similar structure,
so we have our custom components and we can create as many of these properties or props as we wish, we
can name them anything we like.
They're not fixed.
Nobody has defined them ahead of time.
In fact, you are the one that's creating this custom Card element ,and you get to specify which attributes
or properties they should have.
But these values for each of these properties then gets passed along when this Card component is created,
and when we output this HTML element, we can incorporate those properties into the creation of that element.
And it's usually via an input called props.
So the easiest way to imagine it is just simply that you're creating a new JavaScript object with these
key and value pairs, and then that whole object gets sent over as the props object and then you can tap
into it using .name, .telephone,
as long as they match up with the names in your component element. In the next lesson, we're going to
test out your understanding of props, and you're going to be using everything you learn here to complete
a challenge and build out a fully-fledged Contacts app. So for all of that and more, I'll see you there.