Learn React and Javascript by building a card list
This article assumes prior knowledge of react.js
At the end of this article I hope you will learn a thing or two about how to keep domain (business) logic away from react component and hence making them much testable and easy to reason about. Fire up your favorite code editor and let’s get cracking .
In this article you will learn how to build a simple but useful react.js
application. Below is a summary of the features that we will be implementing:
- List cards based on
json
data and implement pagination by showing 12 items per page. - Apply different background color to cards based on the value of a field (
color_id
). - Implement filtering based on a couple of fields.
Despite being small, the size of the application cannot be encapsulated into a single article, hence the intention to split into multiple articles.
Setup Development environment
For code editor, I use VSCode with a couple of useful extensions to make development a breeze. These include
These are the ones that I find useful for my react development. Open your terminal and run the following commands:
npx create-react-app card-game
cd card-game
npm start
To have an awesome development experience, let’s setup Eslint and Prettier. The plan is use Eslint
for formatting our javaScript and Prettier
for everything else. Open up your terminal and run the following commands to install a couple of development dependencies
npm i -D eslint-config-prettier eslint-plugin-prettier prettier
Create a .eslintrc
and add the following lines
{
"extends": ["react-app", "plugin:prettier/recommended"]
}
Add the following to your VSCode user settings
{
"editor.formatOnSave": true,
"[javascript]": {
"editor.formatOnSave": false
},
"eslint.autoFixOnSave": true,
"eslint.alwaysShowStatus": true,
"prettier.disableLanguages": [
"js"
]
}
Using "prettier.disableLanguages": [ "js" ]
will prevent prettier
from running on js
files, since ESLint
got our back. Yay!!
Let’s start coding
Let’s begin by doing some housekeeping. Delete App.css
, App.test.js
, logo.svg
, serviceWorker.js
.
To not waste much time, lets add add our sample json'
file, make Ajax call for it and just display. Under public
directory, create a data
directory and add test.json
.
The final src directory is going to look like below with some few changes
src/
|
|– components/
| |– Filter.js
| |– Pagination.js
| |– PaginationItem.js
|
|
|– model/
| |– constants.js
| |– Game.js
|
|
|– api/
| |– api.js
Update api.js
with the code below
export async function getGames() {
return await gamesData;
}
async function loadData() {
try {
const data = await (await fetch("/data/test.json")).json();
return data;
} catch (e) {
console.error(e);
}
}
/* This is to ensure that a one time call is made for the games data */
const gamesData = loadData();
Now update App.js
as below
import React, { Component } from "react";
import { getGames } from "./api/api";
class App extends Component {
state = {
games: []
};
componentDidMount() {
this.loadGames();
}
loadGames = async () => {
try {
const games = await getGames();
this.setState({ games });
} catch (e) {
console.error(e);
}
};
render() {
const { games } = this.state;
return (
<div className="App">
<pre>{JSON.stringify(games, null, 4)}</pre>
</div>
);
}
}
export default App;
This is as simple as it can get. From the previous command npm start
, your browser should be showing the json
test data. How often do JavaScript developers wish all json
API’s used camel-casing for keys!. For example we prefer firstName
over first_name
. Infant some linters will scream at you for doing otherwise. Let’s fix that now by adding constants.js
and Game.js
under the model directory
Wondering where I got those fancy 🙃 color names, you can find that here.
Each object in the test.json
will be mapped over to return an instance of Game
. Let’s not update our api.js
to reflect the changes. In apiljs
update the line return data;
with return data.map(game => new Game(game));
Please make sure to import Game.js
Now let’s update App.js
to display each item as a card. Add renderCards
method and also update render
method as below:
renderCards() {
const { games } = this.state;
if (!games.length) {
return <div>No Items Found...</div>;
}
return games.map(({ id, color }) => (
<div
key={id}
className="games__item"
style={{ backgroundColor: color }}
/>
));
}render() {
return (
<div className="container">
<div className="games">{this.renderCards()}</div>
</div>
);
}
With Game.js
we have extracted any logic relating to color mapping, hence making our react component much easy to reason about. Since this tutorial isn’t about how to style react components, you can find the css
file here
Now let’s proceed to add pagination. Add/update Pagination.js
and PaginationItem.js
with the following code:
Not sure about you, but I find Array.from({ length: someNumber}, mapFn)
to be an interesting way of generating sequence of numbers and to map over it. To be able to highlight the current page, I also pass selected
prop. Please find the code for PaginationItem.js
below.
Don’t forget to install classnames
package with the following command npm i -S classnames
. To fully integrate pagination, let’s update api.js
and App.js
I always try as much as possible to free my react component from domain logic, hence the reason for adding the convenient total
property in getGames
method. Whew 😅, let’s add the final update for App.js
and call it a day.
Notice that size
is defined as a class property instead of on state, since it has nothing to do with further re-rendering of the react component. Let’s call it a wrap. If you read it this far, I hope you found this article useful. I will be posting the final part (with filtering) soon. Thanks a lot for reading and please don’t hesitate to share and comment.
GitHub link to source code: