Binding an array to a set of DOM elements (JSX) in React.js is a common task in app development. Often, you need to list a set of objects and their corresponding attributes, such as those found in product catalogs, member records, or lists of transactions. In this guide, we will take a look at some considerations when binding a list of objects in a React.js component's interface.
Suppose that you are creating a React.js component that lists a set of products a customer can buy in a grocery store. Each product has an id
, name
, and price
. Data might come from anywhere, such as an API or another component. In any case, you can expect that an array of items will look like the following:
1[
2 { id: 1, name: "Apple", price: 25.00 },
3 { id: 2, name: "Oranges", price: 20.00 },
4 { id: 3, name: "Grapes", price: 22.00 }
5]
This type of data will be passed as a props
attribute called items
within your component.
First, create a component that looks like the following:
1import React from 'react';
2
3export default class ItemsList extends React.Component {
4 constructor(props) {
5 super(props);
6
7 this.state = {}
8 }
9
10 render() {
11 return (
12 <table>
13 <thead>
14 <th>
15 Item
16 </th>
17 <th>
18 Price
19 </th>
20 </thead>
21 <tbody>
22 </tbody>
23 </table>
24 );
25 }
26}
Notice that you don't have any state to maintain and that this component returns a single element in the form of a <table>
. Everything will be read from props
instead of state
. Within the <table>
, React.js requires that you include a <tbody>
before inserting rows in it. Otherwise, it will complain that <tr>
is not a valid child element of <table>
.
Instead of rendering the array of items directly to render()
, create a separate function to handle the building of DOM elements:
1renderRows() {
2 return this.props.items.map(function(o) {
3 return <tr key={"item-" + o.id}>
4 <td>{o.name}</td>
5 <td>{o.price}</td>
6 </tr>
7 });
8}
Notice first that the code references this.props
and assumes that it will have an attribute items
. Since it's calling from this.props
, it expects that this data will be passed from an external component. Second, the code uses the map
function of a JavaScript array to iterate through this.props.items
, which accepts a function that returns a <tr>
element. Finally, the <tr>
element will contain a key
attribute. This is a requirement for React.js wherein each child element of a parent element that is dynamically generated has to be assigned a key unique within the parent element. Since it is assumed that each item will contain an id
unique to it, the code uses that information to generate the key
value of item-someItemId
.
Invoke the function within the component's render()
inside the <tbody>
tag:
1<tbody>
2 {this.renderRows()}
3</tbody>
These items will change if a component calling ItemsList
passes a new set of values for items
via props
.
1import React from 'react';
2
3export default class ItemsList extends React.Component {
4 constructor(props) {
5 super(props);
6
7 this.state = {}
8 }
9
10 renderRows() {
11 return this.props.items.map(function(o) {
12 return <tr key={"item-" + o.id}>
13 <td>{o.name}</td>
14 <td>{o.price}</td>
15 </tr>
16 });
17 }
18
19 render() {
20 return (
21 <table>
22 <thead>
23 <th>
24 Item
25 </th>
26 <th>
27 Price
28 </th>
29 </thead>
30 <tbody>
31 {this.renderRows()}
32 </tbody>
33 </table>
34 );
35 }
36}
Suppose that you want to test it out. From an external JavaScript section in your app, invoke ItemsList
with some data in a DOM element react-root-div
:
1var items = [
2 { id: 1, name: "Apple", price: 25.00 },
3 { id: 2, name: "Oranges", price: 20.00 },
4 { id: 3, name: "Grapes", price: 22.00 }
5];
6
7ReactDOM.render(
8 <ItemsList items={items} />,
9 document.getElementById("react-root-div")
10);
You should see the table render with the name of the item in the first column and its price in the second column. To add more rows to the table, add more objects to items
, making sure that each object has an id
different from the existing objects in the array.
In this guide, you've created a component that has no state but populates a list of JavaScript objects often derived from a JSON object. The component renders these items dynamically, and each child element rendered should have a unique key within its parent element. Because it is a stateless component, you can easily plug this component in other parts of your React.js app that need a list rendered of items.
For an extra challenge, see if you can integrate this in your own React.js app where data is coming from an external API instead of being hardcoded.