📜 ⬆️ ⬇️

React Tutorial, Part 9: Component Properties

In today's part of the translation of the React course, we’ll talk about the properties of the components. This is one of the most important concepts reflected in this library.

image

Part 1: Course Overview, React, ReactDOM, and JSX Reasons
Part 2: Functional Components
Part 3: Component Files, Project Structure
Part 4: Parent and Child Components
Part 5: Getting Started on a TODO Application, Basics of Styling
Part 6: Some of the features of the course, JSX and JavaScript
Part 7: Inline Styles
Part 8: continued work on the TODO application, familiarity with the properties of components
Part 9: Component Properties
Part 10: Workshop on working with the properties of components and styling
Part 11: dynamic markup generation and the map array method
Part 12: workshop, the third stage of work on the TODO application
Part 13: Class Based Components
Part 14: Workshop on Class Based Components, Component State
Part 15: workshops on working with the state of components
Part 16: the fourth stage of the work on the TODO application, event handling


Lesson 19. Component Properties in React


Original

Create a new project using create-react-app and change the code of several standard files from the src folder.

Here is the code for the index.js file:

 import React from "react" import ReactDOM from "react-dom" import "./index.css" import App from "./App" ReactDOM.render(<App />, document.getElementById("root")) 

Here are the styles that are described in the index.css file:

 body { margin: 0; } .contacts { display: flex; flex-wrap: wrap; } .contact-card { flex-basis: 250px; margin: 20px; } .contact-card > img { width: 100%; height: auto; } .contact-card > h3 { text-align: center; } .contact-card > p { font-size: 12px; } 

Here is the code found in the App.js file:

 import React from "react" function App() {   return (       <div className="contacts">           <div className="contact-card">               <img align="center" src="http://placekitten.com/300/200"/>               <h3><font color="#3AC1EF">▍Mr. Whiskerson</font></h3>               <p>Phone: (212) 555-1234</p>               <p>Email: mr.whiskaz@catnap.meow</p>           </div>                     <div className="contact-card">               <img align="center" src="http://placekitten.com/400/200"/>               <h3><font color="#3AC1EF">▍Fluffykins</font></h3>               <p>Phone: (212) 555-2345</p>               <p>Email: fluff@me.com</p>           </div>                     <div className="contact-card">               <img align="center" src="http://placekitten.com/400/300"/>               <h3><font color="#3AC1EF">▍Destroyer</font></h3>               <p>Phone: (212) 555-3456</p>               <p>Email: ofworlds@yahoo.com</p>           </div>                     <div className="contact-card">               <img align="center" src="http://placekitten.com/200/100"/>               <h3><font color="#3AC1EF">▍Felix</font></h3>               <p>Phone: (212) 555-4567</p>               <p>Email: thecat@hotmail.com</p>           </div>       </div>   ) } export default App 

This is how the application will look like in a browser.


Application page in the browser

After analyzing the code and appearance of the application, it is possible to conclude that it would be good to use special components for the output of cards with information about animals. Now these elements are formed by means of the App component. Considering what we talked about in previous lessons, you can go further - think about a universal component that can be customized by passing attributes or properties to it.

In our application there are cards with images of cats, their names and contact information of their owners (and maybe - themselves) - telephone and email address. In order to create a component that will later become the basis for all such cards, you can take one of the markup fragments returned by the App component. For example - this:

 <div className="contact-card">   <img align="center" src="http://placekitten.com/300/200"/>   <h3><font color="#3AC1EF">▍Mr. Whiskerson</font></h3>   <p>Phone: (212) 555-1234</p>   <p>Email: mr.whiskaz@catnap.meow</p> </div> 

The App returns four such blocks, each of them could be used to create an independent component, but this approach does not suit us. Therefore, we will create one component that will become the basis of all the cards displayed by the application. To do this, create a new component file in the src folder, ContactCard.js and place into it the code that returns the first <div> element returned by the App component, the code of which is shown above. Here is the code for the component ContactCard :

 import React from "react" function ContactCard() {   return (       <div className="contact-card">           <img align="center" src="http://placekitten.com/300/200"/>           <h3><font color="#3AC1EF">▍Mr. Whiskerson</font></h3>           <p>Phone: (212) 555-1234</p>           <p>Email: mr.whiskaz@catnap.meow</p>       </div>   ) } export default ContactCard 

It is clear that if you create several copies of this component, then all of them will contain the same data, since this data is rigidly specified in the component code. And we would like that, when creating different instances of this component, we could customize the data it displays. The point is that the component could be passed certain properties that it can then use.

We work with functional components that are common JS functions in which, using the React library, you can use special constructs. As you know, functions can take arguments, although they can be used without arguments. The analogy of our component ContactCard , in the form in which it now exists, can be such a simple function, which, without taking anything, simply returns the sum of two numbers:

 function addNumbers() {   return 1 + 1 } 

It can be used to find out the sum of the numbers 1 and 1, but, for example, in order to add 1 and 2, using functions that do not accept any input data, we would have to write a new function. It is quite obvious that such an approach will lead to huge inconveniences if you need to add different numbers, so in such a situation it would be reasonable to create a universal function for adding numbers that takes two numbers and returns their sum:

 function addNumbers(a, b) {   return a + b } 

What this function returns will depend on the arguments passed to it when it is called. Creating React-components, we can go exactly the same way.

We import the App.js component ContactCard and return four of its instances, while not removing the code that forms the cards on the application page:

 import React from "react" import ContactCard from "./ContactCard" function App() {   return (       <div className="contacts">           <ContactCard />           <ContactCard />           <ContactCard />           <ContactCard />           <div className="contact-card">               <img align="center" src="http://placekitten.com/300/200"/>               <h3><font color="#3AC1EF">▍Mr. Whiskerson</font></h3>               <p>Phone: (212) 555-1234</p>               <p>Email: mr.whiskaz@catnap.meow</p>           </div>                     <div className="contact-card">               <img align="center" src="http://placekitten.com/400/200"/>               <h3><font color="#3AC1EF">▍Fluffykins</font></h3>               <p>Phone: (212) 555-2345</p>               <p>Email: fluff@me.com</p>           </div>                     <div className="contact-card">               <img align="center" src="http://placekitten.com/400/300"/>               <h3><font color="#3AC1EF">▍Destroyer</font></h3>               <p>Phone: (212) 555-3456</p>               <p>Email: ofworlds@yahoo.com</p>           </div>                     <div className="contact-card">               <img align="center" src="http://placekitten.com/200/100"/>               <h3><font color="#3AC1EF">▍Felix</font></h3>               <p>Phone: (212) 555-4567</p>               <p>Email: thecat@hotmail.com</p>           </div>       </div>   ) } export default App 

Now let's work on the code used to create instances of the ContactCard component. By creating ordinary HTML elements, we can customize their attributes that affect their behavior and appearance. The names of these attributes are rigidly specified by the standard. In the case of components, you can use exactly the same approach, with the only difference that we invent the attribute names ourselves, and decide for ourselves how exactly they will be used in the component code.

Each of the cards contains four pieces of information that, from card to card, can vary. This is the image of the cat and its name, as well as the phone and email address. Let the cat's name be contained in the name property, the image address in the imgURL property, the phone in the phone property, and the email address in the email property.

We will set these properties to instances of ContactCard components and, as data is transferred from code that already exists in App , we will delete its corresponding fragments. As a result, the App component code will look like this:

 import React from "react" import ContactCard from "./ContactCard" function App() {   return (       <div className="contacts">           <ContactCard               name="Mr. Whiskerson"               imgUrl="http://placekitten.com/300/200"               phone="(212) 555-1234"               email="mr.whiskaz@catnap.meow"           />                     <ContactCard               name="Fluffykins"               imgUrl="http://placekitten.com/400/200"               phone="(212) 555-2345"               email="fluff@me.com"           />                     <ContactCard               name="Destroyer"               imgUrl="http://placekitten.com/400/300"               phone="(212) 555-3456"               email="ofworlds@yahoo.com"           />                     <ContactCard               name="Felix"               imgUrl="http://placekitten.com/200/100"               phone="(212) 555-4567"               email="thecat@hotmail.com"           />                 </div>   ) } export default App 

True, the mere transfer of properties to a component is not enough for them to be used in it. The page that will be generated by the above App component will contain four identical cards, the data of which are specified in the code of the ContactCard component, which does not yet know what to do with the properties transferred to it.


Card data is hard coded in the code, the component does not know how to work with the properties passed to it

Therefore, it is now time to talk about how the ContactCard component can work with the properties passed to it when creating its instances.

We proceed to the solution of this problem by specifying, when the ContactCard function is ContactCard , that it takes the props parameter. In this case, the component code will look like this:

 import React from "react" function ContactCard(props) {   return (       <div className="contact-card">           <img align="center" src="http://placekitten.com/300/200"/>           <h3><font color="#3AC1EF">▍Mr. Whiskerson</font></h3>           <p>Phone: (212) 555-1234</p>           <p>Email: mr.whiskaz@catnap.meow</p>       </div>   ) } export default ContactCard 

In fact, this parameter can be called whatever you like, but in React it is customary to call it props , and those properties that we are talking about here are often called simply “props”.

The props parameter is an object. The properties of this object are the properties that were passed to the component when creating its instance. That is, for example, in our props object props will be a property props.name , containing the name of the cat, passed to the component when creating its instance. In addition, he will have the properties props.imgUrl , props.phone , props.email . To verify this, add the console.log(props) command to the top of the ContactCard function.

 import React from "react" function ContactCard(props) {   console.log(props)   return (       <div className="contact-card">           <img align="center" src="http://placekitten.com/300/200"/>           <h3><font color="#3AC1EF">▍Mr. Whiskerson</font></h3>           <p>Phone: (212) 555-1234</p>           <p>Email: mr.whiskaz@catnap.meow</p>       </div>   ) } export default ContactCard 

This will allow the props object received by the component to be output to the console.


Props object in console

Here you can see the output of four objects from ContactCard.js . There are so many of them because we create four instances of the component ContactCard .

All this gives us the opportunity to use in the component code, instead of hard-coded values, what is passed to it when creating its instance, available as properties of the props object.

What if we try to use the props.imgUrl property props.imgUrl this:

 <img align="center" src=props.imgUrl/> 

At first glance, such a construction may work, but recall that here we need to use an entity from JavaScript in JSX code. We have talked about how this is done in a previous lesson. Namely, in our case, the property of the object must be enclosed in braces:

 <img align="center" src={props.imgUrl}/> 

We will rework on the same principle as other elements returned by the component, after which its code will look like the following:

 import React from "react" function ContactCard(props) {   return (       <div className="contact-card">           <img align="center" src={props.imgUrl}/>           <h3><font color="#3AC1EF">▍{props.name}</font></h3>           <p>Phone: {props.phone}</p>           <p>Email: {props.email}</p>       </div>   ) } export default ContactCard 

Please note that we left Phone: and Email: with spaces following them in the fields for phone and email addresses, as these texts are used in all components. If you now look at the application page, you can see that it contains four different cards.


Page formed using the universal component

Our component accepts a total of four properties. What if a certain component needs, for example, to pass 50 properties? Perhaps, it will be inconvenient to transfer each such property in a separate line, as is done in the App component. In such cases, you can use another way of passing properties to components. It lies in the fact that when creating an instance of a component, it is not a property list that is passed to it, but an object with properties. Here is how it might look in the first component:

 import React from "react" import ContactCard from "./ContactCard" function App() {   return (       <div className="contacts">           <ContactCard               contact={{                 name: "Mr. Whiskerson",                 imgUrl: "http://placekitten.com/300/200",                 phone: "(212) 555-1234",                 email: "mr.whiskaz@catnap.meow"               }}           />                     <ContactCard               name="Fluffykins"               imgUrl="http://placekitten.com/400/200"               phone="(212) 555-2345"               email="fluff@me.com"           />                     <ContactCard               name="Destroyer"               imgUrl="http://placekitten.com/400/300"               phone="(212) 555-3456"               email="ofworlds@yahoo.com"           />                     <ContactCard               name="Felix"               imgUrl="http://placekitten.com/200/100"               phone="(212) 555-4567"               email="thecat@hotmail.com"           />                 </div>   ) } export default App 

This is not to say that this approach significantly reduced the amount of code used to describe the component instance. The fact is that the properties passed to the component are still rigidly defined in the code, although we pass only one object to the component. The advantages of this approach can be felt in situations where the data for a component is obtained from some external sources. For example, from a JSON file.

During the modification of the App component code used to create the first instance of the ContactCard component, the correct operation of the application was disrupted. Here is what his page will now look like.


Violation of the correct operation of the application

How can this be fixed? In order to understand this, it will be useful to analyze what is happening with the help of the console.log(props) .


Props object analysis

As you can see, the props object of the first component is different from the same object of the second and the following components.

In the ContactCard component ContactCard we use the props object based on the assumption that it has the properties name , imgUrl and the like. Here, the first component receives only one property - contact . This leads to the fact that the props object has only one property - contact , which is an object, and in the component code, work with such a structure is not provided.

To transfer our component to the model of using only one contact property-object containing other properties is quite simple. To do this, for example, to access the name property, it suffices to use the construction of the form props.contact.name in the component code. Similar designs allow you to work properly with other properties we need.

We will rework the component code taking into account the transfer to it of the only contact property-object containing other properties:

 import React from "react" function ContactCard(props) {   console.log(props)   return (       <div className="contact-card">           <img align="center" src={props.contact.imgUrl}/>           <h3><font color="#3AC1EF">▍{props.contact.name}</font></h3>           <p>Phone: {props.contact.phone}</p>           <p>Email: {props.contact.email}</p>       </div>   ) } export default ContactCard 

The first component will now have to be displayed normally, but we will not see this, at this stage of working on the project, as the system will inform us about a variety of errors related to the fact that several instances of the ContactCard component created in the App component do not receive the property- contact object. When executing code, this property will be set to undefined . As a result, an attempt is made to refer to a certain property of the value undefined , which leads to an error. Fix this by reworking the App component code responsible for generating ContactCard components:

 import React from "react" import ContactCard from "./ContactCard" function App() {   return (       <div className="contacts">           <ContactCard               contact={{                 name: "Mr. Whiskerson",                 imgUrl: "http://placekitten.com/300/200",                 phone: "(212) 555-1234",                 email: "mr.whiskaz@catnap.meow"               }}           />                     <ContactCard               contact={{                 name: "Fluffykins",                 imgUrl: "http://placekitten.com/400/200",                 phone: "(212) 555-2345",                 email: "fluff@me.com"               }}           />                     <ContactCard               contact={{                 name: "Destroyer",                 imgUrl: "http://placekitten.com/400/300",                 phone: "(212) 555-3456",                 email: "ofworlds@yahoo.com"               }}           />                     <ContactCard               contact={{                 name: "Felix",                 imgUrl: "http://placekitten.com/200/100",                 phone: "(212) 555-4567",                 email: "thecat@hotmail.com"               }}           />                 </div>   ) } export default App 

Now the application page will look the same as before.

As usual, it is recommended to experiment on your own with the concepts studied today in order to better understand them. For example, you can work with the code, add new properties that are passed to the component, and try to use them in the component.

Results


Today we learned about the concept of properties that can be passed to React components in order to control their behavior and appearance. These properties resemble attributes of HTML elements, but using properties in components, the programmer decides for himself what meaning they have and what to do with them in the component. The next time you will be waiting for a practical lesson on working with the properties of components and on styling.

Dear readers! How have you experimented with the code of today's example in order to better understand the properties of React components?

Source: https://habr.com/ru/post/436032/