The goal of this step is to add support for deleting individual emails in the UI.
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 06-submit-email-form 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.
In EmailListItem, add a "Delete" button that will call a (newly added) onDelete prop with the email ID when clicked:
export default class EmailListItem extends PureComponent {
static propTypes = {
email: EMAIL_PROP_TYPE.isRequired,
onDelete: PropTypes.func.isRequired,
onSelect: PropTypes.func
}
// other helper methods
_handleDelete(e) {
e.stopPropagation();
this.props.onDelete(this.props.email.id);
}
render() {
let {email: {from, subject}} = this.props;
return (
<div className="email-list-item" onClick={this._handleClick.bind(this)}>
<span>{from}</span>
<span>{subject}</span>
<button onClick={this._handleDelete.bind(this)}>Delete</button>
</div>
);
}
}In EmailList, add a new onItemDelete prop that is passed to each <EmailListItem />'s onDelete prop:
export default class EmailList extends PureComponent {
static propTypes = {
emails: PropTypes.arrayOf(EMAIL_PROP_TYPE),
onItemDelete: PropTypes.func.isRequired,
onItemSelect: PropTypes.func.isRequired
};
render() {
let {emails, onItemSelect, onItemDelete} = this.props;
let emailComponents = emails.map(email =>
<li key={email.id}>
<EmailListItem
email={email}
onSelect={onItemSelect}
onDelete={onItemDelete}
/>
</li>
);
return (
<ul className="email-list">
{emailComponents}
</ul>
);
}
}In the top-level App, add a _handleItemDelete() helper method that is passed as onItemDelete to <EmailList />. Initially have _handleItemDelete() log to the console the ID of the email to delete:
export default class App extends PureComponent {
// initialize state
// other helper methods
_handleItemDelete(emailId) {
console.log(emailId);
}
render() {
let {emails, selectedEmailId} = this.state;
let selectedEmail = emails.find(email => email.id === selectedEmailId);
let emailViewComponent;
if (selectedEmail) {
emailViewComponent = (
<EmailView
email={selectedEmail}
onClose={this._handleEmailViewClose.bind(this)}
/>
);
}
return (
<main className="app">
<EmailList
emails={emails}
onItemDelete={this._handleItemDelete.bind(this)}
onItemSelect={this._handleItemSelect.bind(this)}
/>
{emailViewComponent}
<EmailForm onSubmit={this._handleFormSubmit.bind(this)} />
</main>
);
}
}At this point, you should be able to click a "Delete" button for one of the email items and see the ID logged to the console. What we need to do next is to actually remove the email from this.state.emails so that it no longer shows up in the list:
export default class App extends PureComponent {
// initialize state
// other helper methods
_handleItemDelete(emailId) {
this.setState(({emails}) => ({
// "delete" the email by returning a filtered list that doesn't include it
emails: emails.filter(email => email.id !== emailId)
}));
}
// render()
}Once again we're using the "updater function" version of setState to update the emails state because we're using the current version of emails to determine the next version of emails. And as always, we never want to mutate state or properties within state. So before we remove the email to delete from this.state.emails we first need to make a copy of emails. A quick way to do this in a single step is using .filter() to return a filtered list that doesn't include the email to delete.
Now clicking a "Delete" button for one of the emails items should immediately remove it from the list. Using the React Developer Tools, watch how the deleted email item is optimally removed from the list. Nothing else in the UI is updated thanks to the reconciler (aka "Virtual DOM").
- Add a "Delete" button to
EmailViewthat hooks into_handleItemDelete()(EmailViewwill need to expose anonDeletecallback prop too) - Update
_handleItemDelete()to resetthis.state.selectedEmailIdso that the email in the email view doesn't still show after being deleted
Go to Step 8 - Interacting with APIs.
Got questions? Need further clarification? Feel free to post a question in Ben Ilegbodu's AMA!