Learn React and Javascript by building a card list

David Blay
4 min readDec 17, 2018

--

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:

  1. List cards based on json data and implement pagination by showing 12 items per page.
  2. Apply different background color to cards based on the value of a field ( color_id).
  3. Implement filtering based on a couple of fields.
Preview of the card list with filtering

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:

--

--

David Blay

I Pray...I Code...I Love | JavaScripter | Lifelong Learner