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

Original author: Bob Ziroll
  • Transfer
  • Tutorial
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 generation of JSX markup describing sets of the same type of elements. → Part 1: course overview, reasons for the popularity of React, ReactDOM and JSXPart 2: functional componentsPart 3: component files, project structurePart 4: parent and child componentsPart 5: starting work on a TODO application, basics of stylingPart 6: About some features of the course, JSX and JavaScriptPart 7: Inline Styles

image








Part 8: continued work on a TODO application, familiarity with the properties of components
Part 9: properties of components
Part 10: a workshop on working with properties of components and styling
Part 11: dynamic formation of markup and the array method map
Part 12: workshop, third stage towards TODO-application
Part 13: components based on classes
Part 14: workshop on the components, based on classes state components
Part 15: workshops to work with components state
Part 16: fourth stage towards TODO-attached eat, event handling
Part 17: fifth stage of work on the TODO application, modification of the state of the components
Part 18: sixth stage of work on the TODO application
Part 19: methods of the component life cycle
Part 20: first lesson on conditional rendering
Part 21: second lesson and workshop on conditional rendering
Part 22: the seventh stage of working on a TODO application, loading data from external sources
Part 23: the first session on working with forms
Part 24: the second session on working with forms
Part 25: a workshop on working with forms
Part 26: application architecture, n Container / Component
Part 27: course project

Lesson 21: Dynamic Markup Formation and the Map Array Method


Original

Let's continue the work from the point where we left off, carrying out the previous practical task. Recall that then the file code App.jslooked like this:

import React from"react"import Joke from"./Joke"functionApp() {
    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 component Appdisplays a set of components Joke. Here’s how the application page looks like at this stage.


Application page

Some of these components are passed propertiesquestionandpunchLine, and some - onlypunchLine. Now the values ​​of these properties are specified in the code for creating component instancesJokeas 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 facilities 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 perform requests to the API, so now we, in the role of the data source, will use the file with the data that could be obtained as a result of parsing the server's JSON response. Namely, it will be a filejokesData.js with the following content:

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."
    }
]
exportdefault jokesData

This file will be located in the directory of srcour project.


The new file in the 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 an array from this filejokesData. 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 a call to one or another standard method will do with the elements of an 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 create 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 not met with the methods of arrays - such as map(), filter(), reduce()and others - it is recommended to deal with them.

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

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

import jokesData from"./jokesData"

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

jokesData.map(joke => {
})

Notice that we pass the map()arrow function to the 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 method map(), we want to return a new instance of the component Joketo which the properties questionand the punchLinearray element received in it are transferred jokesData. Here is what it might look like:

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

This code can be reduced if you consider two facts. First, it returnreturns 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, you can do without a keyword returnand without curly brackets. In addition, recall that as a result of the method map(), 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 constant jokeComponentswill now contain an array, each element of which is a description of the component instance Jokewith the properties passed to it questionand punchLine.

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 file code will now look App:

import React from"react"import Joke from"./Joke"import jokesData from"./jokesData"functionApp() {
    const jokeComponents = jokesData.map(joke => <Joke question={joke.question} punchLine={joke.punchLine} />)
    
    
    return (
        <div>
            {jokeComponents}
        </div>
    )
}
exportdefault 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 property key. We will not go into details as to why React expects a unique property keyfor repeating 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 method map(), we need to pass a property to the instances key. In this case, such a property can be passed both to the component instance itself, and, for example, to the tag containing the <div>component code. It does not play a special role.

So, the property keymust be assigned some unique value. As a rule, in the data objects obtained from the API, there are some identifiers (properties likeid). The main thing for us is their uniqueness. For example, we could assign a property a keyvalue joke.question— all the texts in these properties in our application are unique. But we will do otherwise. Recall how objects with data from the array that we exported from a file look like jokesData.js. 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 a property id, the uniqueness of which we maintain on our own. It is the values ​​of such properties that can be used as values ​​for a property key.

Now the code for creating an array of component instances in App.jswill take the following form:

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 page of the application in the browser and check the contents of the console, it turns out that the property notification keydisappeared.

After all the transformations to which we have subjected the project, the appearance of the application page has not changed. However, the component code has Appbecome 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. It is under this scheme that real applications work.

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

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

If you want, you can experiment with these methods. Let's say try to use the method filter()and remove from the output formed by the componentApp, those component instances Jokewhose property questiondoes not exceed the specified length. Or do so in conclusion would get only the components that are set and the property question, and the property punchLine.

Results


Today we talked about using the standard array method map()to generate lists of components, and also discussed the possibilities that other standard array methods give 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?


Also popular now: