📜 ⬆️ ⬇️

React tutorial, part 11: dynamic markup generation and the map array method

In today's part of the translation of the React course, we will talk about using the standard array method map () to organize the dynamic formation of JSX markup describing sets of similar elements.

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 21: Dynamic markup generation and the map array method


Original

We will continue the work from the point at which we stopped, carrying out the previous practical task. Recall that then the code of the App.js file looked like this:

 import React from "react" import Joke from "./Joke" function App() {   return (       <div>           <Joke punchLine="It's hard to explain puns to kleptomaniacs because they always take things literally." />                     <Joke               question="What's the best thing about Switzerland?"               punchLine="I don't know, but the flag is a big plus!"           />                     <Joke               question="Did you hear about the mathematician who's afraid of negative numbers?"               punchLine="He'll stop at nothing to avoid them!"           />                     <Joke               question="Hear about the new restaurant called Karma?"               punchLine="There's no menu: You get what you deserve."           />                     <Joke               question="Did you hear about the actor who fell through the floorboards?"               punchLine="He was just going through a stage."           />                     <Joke               question="Did you hear about the claustrophobic astronaut?"               punchLine="He just needed a little space."           />                 </div>   ) } export default App 

The App component displays a set of Joke components. Here’s how the application page looks at this stage.


Application page

Some of these components are given the question and punchLine , and some are only the punchLine . Now the values ​​of these properties are set in the code for creating instances of the Joke component in plain text. In reality, the bulk of the data that is displayed on the React-application pages, enters the application as a result of HTTP requests to certain APIs. These APIs are supported by server tools that take information from databases, format it as JSON code, and send this code to client parts of applications. We have not yet reached such a level to fulfill requests to the API, so now we, in the role of a data source, will use a file with data that could be obtained as a result of parsing the server's JSON response. Namely, it will be jokesData.js file with the following contents:

 const jokesData = [   {       id: 1,       punchLine: "It's hard to explain puns to kleptomaniacs because they always take things literally."   },   {       id: 2,       question: "What's the best thing about Switzerland?",       punchLine: "I don't know, but the flag is a big plus!"   },   {       id: 3,       question: "Did you hear about the mathematician who's afraid of negative numbers?",       punchLine: "He'll stop at nothing to avoid them!"   },   {       id: 4,       question: "Hear about the new restaurant called Karma?",       punchLine: "There's no menu: You get what you deserve."   },   {       id: 5,       question: "Did you hear about the actor who fell through the floorboards?",       punchLine: "He was just going through a stage."   },   {       id: 6,       question: "Did you hear about the claustrophobic astronaut?",       punchLine: "He just needed a little space."   } ] export default jokesData 

This file will be located in the src directory of our project.


New file in src folder

In fact, it contains an array of objects. A similar array can be obtained by parsing the JSON data received from some API. We export the jokesData array from this file. If necessary, we can import this file into the component in which it is needed, and imagine that we are not working with data taken from the file, but with what returned to us some kind of API.

Now that we have an array of source data, let's think about how to turn this data into a set of instances of React components.

Many developers say that, by mastering React, they learned JavaScript better. The reason for this is that actions like the one we are going to talk about in other frameworks, like Angular and Vue, are performed using some special means. And in React, this is done using regular javascript.

In particular, we plan to use some standard array methods that are functions of a higher order. These methods can, as arguments, take functions described by programmers. It is these functions that determine what the standard method call will do to the elements of the array.

Suppose we have a numeric array:

 const nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 

We can process this array using the standard array method map() , passing it a certain function that specifies the order of conversion of the elements of this array. In our case, this function will be transferred, one by one, numbers from this array. A function can do anything with them, after which what it returns will fall into a new array, into an element whose index corresponds to the index of the element being processed. If we need to form a new array, whose elements are elements of the original array, multiplied by 2, then it will look like this:

 const doubled = nums.map(function(num) {   return num * 2 }) 

Check the operation of this code:

 console.log(doubled) // [2, 4, 6, 8, 10, 12, 14, 16, 18, 20] 

If you have never met with array methods such as map() , filter() , reduce() and others, it is recommended to deal with them.

Here we will use the map() method to automatically generate a list of component instances.

Let's return to our example. Import the App.js file into the App.js file. This is done like this:

 import jokesData from "./jokesData" 

After that, in the program code, we will be able to work with the jokesData array. Namely, we are going to use the map() method. Here is what the “blank” of this method will look like.

 jokesData.map(joke => { }) 

Notice that we are passing an arrow function to the map() method. In our case, this allows us to make the code more compact. Since the function takes only one parameter ( joke ), we, when it is declared, can do without parentheses.

From the function passed to the map() method, we want to return a new instance of the Joke component, to which the question and punchLine properties of the punchLine array element received into it are jokesData . Here is what it might look like:

 jokesData.map(joke => {   return (   <Joke question={joke.question} punchLine={joke.punchLine} />   ) }) 

This code can be shortened if we consider two facts. First, return returns only one element, so you can put this element immediately after return , getting rid of the parentheses. Secondly, the switch function contains only the operation of returning a certain value, therefore, when declaring such a function, it is possible to do without the keyword return and without curly brackets. In addition, recall that as a result of the map() method, a new array is formed. This array needs to be saved somewhere. All these considerations lead us to the following:

 const jokeComponents = jokesData.map(joke => <Joke question={joke.question} punchLine={joke.punchLine} />) 

The jokeComponents constant jokeComponents now contain an array, each element of which is a description of an instance of the Joke component with the question and punchLine properties passed to it.

What do we do now with this array of components? React makes it very convenient to work with such arrays. Namely, we are talking about the fact that such an array can be used in JSX-code. This is how the App file code will now look:

 import React from "react" import Joke from "./Joke" import jokesData from "./jokesData" function App() {   const jokeComponents = jokesData.map(joke => <Joke question={joke.question} punchLine={joke.punchLine} />)       return (       <div>           {jokeComponents}       </div>   ) } export default App 

The application page will then look the same as before, however, the following warning can be seen in the browser console:

 Warning: Each child in an array or iterator should have a unique "key" prop. Check the render method of `App`. See https://fb.me/react-warning-keys for more information.   in Joke (at App.js:7)   in App (at src/index.js:6) 

Its meaning boils down to the fact that the elements of the array must have a unique key property. We will not go into details as to why React expects the presence of a unique key property on duplicate components. It is enough for us to take into account the fact that when performing mass creation of instances of components, like the one we just performed using the map() method, we need to pass the key property to instances. In this case, such a property can be passed to the component instance itself, and, for example, to the <div> , which contains the component code. It does not play a special role.

So, the key property needs to be assigned a kind of unique value. As a rule, in the data objects obtained from the API, there are some identifiers (properties like id ). The main thing for us is their uniqueness. For example, we could assign the value of joke.question to the key property — all texts in these properties in our application are unique. But we will do otherwise. Remember how the objects with data from the array look like we exported from the jokesData.js file. Here is his fragment:

 const jokesData = [   {       id: 1,       punchLine: "It's hard to explain puns to kleptomaniacs because they always take things literally."   },   {       id: 2,       question: "What's the best thing about Switzerland?",       punchLine: "I don't know, but the flag is a big plus!"   }, ... ] 

Each object has an id property, the uniqueness of which we maintain on our own. It is the values ​​of such properties that can be used as the values ​​for the key property.

Now the code for creating an array of component instances in App.js will look like this:

 const jokeComponents = jokesData.map(joke => <Joke key={joke.id} question={joke.question} punchLine={joke.punchLine} />) 

If you make this change to the code, take a look at the application's page in the browser and check the contents of the console, it turns out that the notification about the key property has disappeared.

After all the transformations to which we subjected the project, the appearance of the application page has not changed. However, the App component code has become much shorter and clearer, and the data to form the list of components is now taken from something that strongly resembles an external data source. This is the scheme used by real applications.

In addition, it should be noted that the core of the above code modification was the use of the standard method of arrays map() . We used the method of generating a list of instances of the Joke component in the App component, but nothing prevents us, if necessary, from using the same approach in the Joke component, which can form its own list of instances of a certain component based on the data passed to it.

In this case, as we have said, among the standard methods of arrays, you can find other interesting tools. For example, the sort() method sort() can be used to sort the elements of arrays according to a certain sign. The filter() method can be used to select only those elements of an array that meet certain criteria. All this also applies when working with arrays that contain instances of components.

If you want, you can experiment with these methods. Say, try using the filter() method and remove from the output generated by the App component those instances of the Joke component whose question property does not exceed the specified length. Or make it so that only components for which both the question property and the punchLine property are punchLine .

Results


Today we talked about using the standard method of arrays map() for building lists of components, and also discussed the possibilities that the use of other standard array methods gives us. The next time you are waiting for a practical lesson on the material studied today.

Dear readers! How would you approach the task of displaying by the App component only those instances of the Joke component whose length of the question property value exceeds the specified length?

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