The goal of this step is to practice transforming lists of data into lists of components which can be included in JSX. As a result, we'll convert the EmailList component from statically rendering the five EmailListItem components to dynamically rendering an arbitrary list of EmailListItem components. We'll also make use of more advanced prop types.
As always, if you run into trouble with the tasks or exercises, you can take a peek at the final source code.
If you didn't successfully complete the previous step, you can jump right in by copying the step and installing the dependencies.
Ensure you're in the root folder of the repo:
cd react-workshopRemove the existing workshop directory if you had previously started elsewhere:
rm -rf workshopCopy the previous step as a starting point:
cp -r 02-components workshopChange into the workshop directory:
cd workshopInstall all of the dependencies (yarn is preferred):
# Yarn
yarn
# ...or NPM
npm installStart the app:
# Yarn
yarn start
# ...or NPM
npm startAfter the app is initially built, a new browser window should open up at http://localhost:3000/, and you should be able to continue on with the tasks below.
The way that you dynamically render multiple elements in React is by putting those elements in an array and rendering the array of components. This differs from traditional template languages where there is some looping construct (such as ng-repeat) and you specify the loop item to display.
In EmailList.js, pull out the raw data that makes up the three EmailListItem components into an EMAILS const array. Use Array.prototype.map to convert the array of data into an array of components:
const EMAILS = [
{
id: 1,
from: 'alittle0@chronoengine.com',
subject: 'Mauris lacinia sapien quis libero'
},
{
id: 2,
from: 'amurray1@mit.edu',
subject: 'Mauris ullamcorper purus sit amet nulla'
},
{
id: 3,
from: 'dmccoy2@bluehost.com',
subject: 'Suspendisse potenti'
},
{
id: 4,
from: 'raustin3@hexun.com',
subject: 'Maecenas rhoncus aliquam lacus'
},
{
id: 5,
from: 'rwagner4@instagram.com',
subject: 'Pellentesque ultrices mattis odi'
}
];
export default class EmailList extends PureComponent {
render() {
let emailComponents = EMAILS.map((email) =>
<li key={email.id}>
<EmailListItem from={email.from} subject={email.subject} />
</li>
);
return (
<ul className="email-list">
{emailComponents}
</ul>
);
}
}Be sure to include the key prop on the <li> elements.
Update EmailListItem to take a single email prop instead of individual props for each email property (don't forget the propTypes!):
export default class EmailListItem extends PureComponent {
static propTypes = {
email: PropTypes.shape({
from: PropTypes.string.isRequired,
subject: PropTypes.string.isRequired
}).isRequired
};
render() {
let {email: {from, subject}} = this.props;
return (
<div className="email-list-item">
<span>{from}</span>
<span>{subject}</span>
</div>
);
}
}The EmailList component will need to be updated to pass the email prop to EmailListItem:
export default class EmailList extends PureComponent {
render() {
let emailComponents = EMAILS.map((email) =>
<li key={email.id}>
<EmailListItem email={email} />
</li>
);
return (
<ul className="email-list">
{emailComponents}
</ul>
);
}
}We're starting to make something that visually looks like a list of emails, but it currently isn't styled at all. The app already comes with component CSS files so we just need to associate them with their corresponding JS files so that the elements will be styled. Simply import the component CSS files in EmailList.js and EmailListItem.js:
EmailList.js
import React, {PureComponent} from 'react'
import PropTypes from 'prop-types'
import EmailListItem from './EmailListItem'
import {EMAIL_PROP_TYPE} from './constants'
// import component CSS file
import './EmailList.css'
export default class EmailList extends PureComponent {
...EmailListItem
import React, {PureComponent} from 'react';
import {EMAIL_PROP_TYPE} from './constants';
// import component CSS file
import './EmailListItem.css';
export default class EmailListItem extends PureComponent {
...- Move the
EMAILSout ofEmailListinto the top-levelApp - Pass
EMAILSinAppas theemailsprop to<EmailList> - Declare a new
emailsprop type usingPropTypes.arrayOf()inEmailList(you can share common prop types withEmailListItemin acomponents/constants.jsfile) - Use
this.props.emails(instead ofEMAILS) in themap()withinrender()ofEmailList - Import component CSS for
App.js,EmailForm.jsandEmailView.js
Go to Step 4 - Email View.
Got questions? Need further clarification? Feel free to post a question in Ben Ilegbodu's AMA!