Message Box is a React application that displays a list of email messages. The resulting output is akin to the common representation of such lists found in email client applications.
This project was bootstrapped with Create React App and uses ES6 syntax.
The following gif
of a screen recording gives an idea of how the rendered list appears in the browser and of how the underlying React components are structured (visible in the open React Developer Tools):
In order to run the application, Node and npm need to be installed on your local machine (it is recommended to use Node >= 6 and npm >= 3).
You then need to clone this repository locally:
git clone git@github.com:zollillo/message-box.git
To install the necessary npm
packages, please run the following command from within the project folder (installing the packages may take one or two minutes 😇):
npm install
Once the installation process has finished, you can run the application with:
npm start
The app then runs in development mode and is accessible in your browser at http://localhost:3000/
.
After cloning the repository and installing all dependencies, the structure of the project should look like the following outline:
message-box/
.gitignore
node_modules/ /* content not shown */
package.json
public/
favicon.ico
index.html
README.md
src/
components/
Message.js
MessageBox.js
MessageList.js
css/
index.css
MessageBox.css
helpers.js
index.js
Since this project is based on Create React App, the following files are mandatory, otherwise the project won't work (for more information about the folder structure of a project built with Create React App see the user guide):
public/index.html
— page templatesrc/index.js
— JavaScript entry point
The JSON
data set that holds our messages describes an array of message objects with the following properties:
[
{
"id": "1234abc",
"date": "2016-02-18T13:52:22.343Z",
"name": "Jane Doe",
"email": "jane.doe@abc.de",
"read": false,
"status": "DRAFT",
"subject": "Lorem ipsum",
"body": "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua."
},
...
]
The application fetches the data using the Fetch API. We provide the URL to our mails.json
file as a property to our top component MessageBox
(see below). This makes it easy to change the URL or replace it with a different endpoint.
Fetching the data happens from within React's lifecycle method componentDidMount()
, which gets called once the component is in the DOM. In this case, we use componentDidMount()
to set the state of the MessageBox
component by getting the message data.
The JSON
data (see above) provides a set of messages that the message box ui displays in a list. The following sections describe the structure of the ui components, the markup and layout, as well as the interaction.
The message box with its list of messages is created by composing multiple React components into one that will be rendered into the page template. The outermost parent component is the MessageBox
component. Inside of this MessageBox
component exists another component called MessageList
. Finally, the MessageList
component renders out a Message
component for each message item in the JSON
data set. The message data is passed via properties in order to access and use it inside the components to show the values and change state (e.g. mark an unread message as read on click).
The following screenshot illustrates the component structure when inspected with React Developer Tools:
Both the MessageBox
and the MessageList
component are merely composed of one <div>
element.
Each Message
component, however, comprises several <div>
and <span>
elements layed out using the Flexbox layout. This allows for aligning the content of each message in a row-oriented, table-cell-like fashion. The horizontal width is divided between three message cells (<div>
elements):
- 25% to display the name and the email address
- 65% to display the subject and the body (overflowing text is truncated)
- 10% to display the date
The <span>
elements help to apply CSS styling such as ::before
and ::after
pseudo elements for enclosing the email address with the characters <
and >
( <jane.doe@abc.de>
) and for coloring the message body text differently than the message subject.
Using React and JSX, it is possible to conditionally render elements inline. This allows us to display either the date
of the email or the word Entwurf
(= German word for 'draft') depending on the status
property of the message. The date
is formatted using Moment.js to make the ISO 8601 date format more readable.
Inside the Message
component:
<div className="message-cell message-date">
{this.state.isDraft ? <mark>Entwurf</mark> : formatDate(message.date)}
</div>
Similarly, a CSS class of unread
is dynamically applied if the value of the message's read
property is false
which results in highlighting the entire message row in bold font.
The screenshot below shows the HTML markup/DOM tree inspected with Chrome Developer Tools (please also refer to the Demo to see the rendered page):
The message properties status
and read
constitute the state of the Message
component:
class Message extends Component {
constructor(props) {
super(props);
// ...
this.state = {
isDraft: this.props.content.status === 'DRAFT',
isUnread: !this.props.content.read
};
}
// ...
}
Over time, the keys and values of the component's state object
can change, and responding to those changes, the component can re-render itself to represent the current or correct state in the ui.
It is possible to click on the messages, and as demonstrated above, this changes the state of unread messages so that the bold font highlighting is disabled.
The onClick
handler of the Message
component:
markMessageAsRead() {
if (this.state.isUnread) {
this.setState((prevState, props) => ({
isUnread: !prevState.isUnread
}));
}
return;
}
Note that in this case, the changes are not persistent, since the application doesn't update values in the JSON
file, i.e. reloading the page results in delivering the original data.
Tested in
- Chrome 55.0.2883.95 (64-bit)
- Firefox 50.1.0
- Safari 10.0.2