✏ Change of Plan
I had originally planned to write more about JavaScript Promises and then proceed to the Fetch API, but I'm getting a bit unsatisfied with only reading about those methods and working on simple code snippets. Reading about concepts makes sense if you start at 0, but at some point, you'll have to use those concepts in a real project, otherwise you'll just forget them.
There are a few more methods related to Promises that I haven't covered, but I'll write about those when I encounter them in an actual project.
The Fetch API is very simple to use and doesn't need much explanation. fetch()
returns a Promise, and does basically the same as what I manually coded with a XMLHttpRequest
.
For these reasons, I've decided to tackle a small project: A Quiz App with React, using the Open Trivia DB. It's obviously not a MERN application, since I'll write no back end code, but this should deepen my understanding of how to fetch data and process it in a React App.
✏ React Quiz App
I won't use create-react-app, but install everything manually. I already did that on Day 3, but this time I'll include some more packages for convenience.
I'll basically follow the steps from this article: How to Create a React Development Build, with some modifications.
Step 1
Creating the project folder and initialising it:
mkdir react-quiz
cd react-quiz
npm init
Step 2
Installing React:
npm i react react-dom
Step 3
Installing everything from Webpack and saving it as dev dependency:
npm i --save-dev webpack webpack-cli html-webpack-plugin webpack-dev-server
Also, some loaders:
npm i --save-dev html-loader css-loader style-loader
Step 4
Next, Babel:
npm i --save-dev @babel/core @babel/preset-env @babel/preset-react babel-loader
Step 5
Installing ESLint as a helping hand:
npm i --save-dev eslint eslint-webpack-plugin eslint-plugin-react babel-eslint
Step 6
Configuration files for Webpack, Babel and ESLint:
webpack.config.js
const HtmlWebPackPlugin = require("html-webpack-plugin");
const ESLintPlugin = require('eslint-webpack-plugin');
module.exports = {
"mode": "development",
"entry": "./src/index.js",
"output": {
"path": __dirname + '/public',
"filename": "bundle.js"
},
"devtool": "source-map",
"module": {
"rules": [
{
"test": /\.(js|jsx)$/,
"exclude": /node_modules/,
"use": {
"loader": "babel-loader"
}
},
{
"test": /\.css$/,
"use": [
"style-loader",
"css-loader"
]
},
{
"test": /\.html$/,
"use": [
{
"loader": "html-loader"
}
]
}
]
},
"plugins": [
new HtmlWebPackPlugin({
template: "./src/index.html",
filename: "./index.html"
}),
new ESLintPlugin({})
]
}
.babelrc
{
"presets": [ "@babel/preset-env", "@babel/preset-react" ]
}
.eslintrc.js
module.exports = {
"env": {
"browser": true
},
"plugins": [ "react" ],
"extends": [
"eslint:recommended",
"plugin:react/recommended"
],
"parser": "babel-eslint"
};
Step 7
Creating a src folder with these files for the basic boilerplate:
- index.js
- index.html
- App.js
- App.scss
Step 8
Check if everything works as it should:
npx webpack
Awesome, index.html
and bundle.js
file successfully created.
Step 9
Adding some scripts in the package.json
:
package.json
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack",
"start": "webpack serve --mode development --open --hot"
}
Step 10
Starting the server 🚀
npm start
I get some warnings in the console that seem to be related to ESLint and that I haven't entirely figured out yet, but the environment is working and I can't wait to start building, so I'll just ignore those 🤟
✏ Components
Checking out the Quiz API documentation, you can select a few options (questions genre, multiple choice yes/no, ...), so I'll make an Options component. Also two stateless components Header and Footer, and the actual Quiz.
✏ Fighting with ESLint
I'm beginning to understand the convenience of create-react-app. With my current setup, ESLint throws tons of errors that (how I'm used to it) should just be warnings. I do understand the no-unused-vars
rule and I do like that ESLint informs me, but while I'm developing, I really don't need to have an error thrown at me each time.
Adjusting the config file to add a set of rules:
.eslintrc.js
module.exports = {
"env": {
"browser": true
},
"plugins": [ "react" ],
"extends": [
"eslint:recommended",
"plugin:react/recommended"
],
"rules": {
"react/prop-types": "off",
"react/jsx-key": "warn",
"no-unused-vars": "warn"
},
"parser": "babel-eslint"
};
✏ Current Code
The App component
The structure is as follows:
App
| Header
| Options
| | Select
| Quiz
| Footer
The Options component
In this component, I want to show different option dropdowns, and update state in the App component accordingly.
I guess I could've gone for the standard <select>
and <option>
HTML tags, but I find that styling those to make them look half-decent is a pain. I understand that a uniform look for form elements makes sense regarding accessibility, but I'm not building anything that'll ever go in production. So I've made my own <Select />
component that only uses <div>
tags.
The current code works, but there's probably no point in posting it now, before some serious refactoring.
✏ Recap
I've learned
- how much I prefer building things over reading documentation when it's not immediately necessary
- how to set up a more sophisticated environment for a React App without create-react-app
- how to configure ESLint
✏ Next:
- writing the code for the actual API call using
fetch()
- displaying the questions
✏ Thanks for reading!
I do my best to thoroughly research the things I learn, but if you find any errors or have additions, please leave a comment below, or @ me on Twitter. If you liked this post, I invite you to subsribe to my newsletter. Until next time 👋
✏ Previous Posts
- Day 1: Introduction, Node.js, Node.js in the terminal
- Day 2:
npm
, node_modules,package.json
andpackage-lock.json
, local vs global installation of packages - Day 3: Create a React app without create-react-app, Webpack, Babel
- Day 4:
npx
and cowsay - Day 5:
npm
vs.npx
,npm audit
, semantic versioning and update rules - Day 6: Call stack, event loop, JavaScript engine, JavaScript runtime
- Day 7: Call stack and event loop in Node.js,
setImmediate()
- Day 8:
setImmediate()
,process.nextTick()
, event loop phases in Node.js - Day 9: Network requests with
XMLHttpRequest
and callbacks - Day 10: Promises
- Day 11: Network requests with
XMLHttpRequest
and Promises