logo

Create a To-do list web app from scratch using React Hooks, Styled-Components and Webpack: Part 1

Front end development is a fast-changing field as a good amount of new frameworks or libraries are released every year. As a result, developers have to keep up with the different new technologies while mastering some of the old ones. This might be hard for beginners who are starting in web development. This tutorial is created and tailored specifically for starters in these libraries.

We will be building a todo list from start to end and we will be building it with the latest libraries such as React, Styled Components and Webpack. I will give you guys a brief introduction to these libraries.

React

React is one of the most popular front end libraries in recent years. It is a javascript library for building UI. We use React to create UI building blocks of webpages which is called Components. With those Components, we can build complex and sophisticated UI.

Styled components

Everyone is familiar with CSS, it is used to make our webpages look good. Styled components are a new approach called CSS-in-JS to style our webpages which is not through CSS files, we will style our html elements in Javascript files. As a result, we do not need to maintain a bunch of CSS files which is a nightmare for complex applications.It creates a collection of components which contain styles instead. It has several advantages such as easy to share code, able to avoid class names collisions, etc.

Webpack

Webpack is one of the most popular Javascript module bundlers. It bundles codes for us to use on the browsers. It works by creating a dependency graph which maps out all the code that your web app is using. With the graph, it creates a bundle with only the code you are using in your web app.


Prerequisite

Basic understanding of following:

  • HTML, CSS and Javascript
  • Terminal
  • Document Object Model API (DOM)

0. Preface

In this section, I will show you how to create a simple webpage with just HTML and JavaScript. It might be helpful to you in the next stage as you would have a better understanding of how things are put together. You could skip this section if you want to set-up the project with a development environment.

0.1 Create a simple HTML page

HTML is the most basic building blocks of the web. HTML defines the structure of a webpage where CSS defines its appearance and Javascript defines how a user can interact with it.

Let's create a HTML file through terminal.

  • Open your favourite terminal.
  • Go to a folder where you want to create this project

    • for example , cd ~/Projects/, as I want to create our project in a folder named Projects
  • Create a empty folder inside our Projects folder which I named as to do.

    • Run mkdir todo. mkdir creates a new folder.
  • Run

    cd {the project name you just created}

    For example, I am running cd todo.

  • In the current directory, run touch index.html which will be our webpage.

    • touch creates a empty file.
  • Run ls to check view the current directory and you will see a index.html that you have just created.
  • Open the todo folder in a editor of your choice. I am using Visual Studio Code.
  • Let’s write some code inside the index.html file.
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>My Todo List</title>
  <meta name="description" content="My Todo list">
  <meta name="author" content="YourName">
</head>
<body>
  <p>Hello world</p>
</body>
</html>

Open the index.html with a browser and You will see Hello world printed on the website.

0.2 Add React

  • Let’s download the react and react-dom libraries via a cdn provided by React.

    • CDN is short for content delivery networks, they are a bunch of servers delivering files to web clients. They are very useful when you want customers around the world accessing your website. Most CDN providers have servers around the world which decreases latency in serving contents to your customers.
<head>
  <meta charset="utf-8">
  <title>My Todo List</title>
  <meta name="description" content="My Todo list">
  <meta name="author" content="YourName">
  <script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
  <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
</head>

0.3 Use React

  • Remove <p>Hello World</p> as we are going to replace that with a same element created by React.
  • Let’s create another script tag at the end of our <body> tag.

    • Javascripts runs inside script tags or in a external file with a source url.
<div id="container"></div>
<script>
  // querySelector is a DOM API method to retrieve DOM elements.
  // To select DOM element with id, a leading # must be added.
  const containerElm = document.querySelector('#container');  
</script>
  • containerElm will be a DOM element which is an entry point for React to inject its elements.
<div id="container"></div>
<script>
  // querySelector is a DOM API method to retrieve DOM elements.
  // To select DOM element with id, a leading # must be added.
  const containerElm = document.querySelector('#container');

  // createElement creates a React element with 3 parameters.
  // 1. type of the element 2. props for the element, 3. children of the element.
  // This could be written is a cleaner form call JSX which we will get to later.
  const Paragraph = React.createElement('p', {}, 'Hello World');
</script>
  • We’ve create our first React element!
  • We will not need to call createElement every time we want to create an element with JSX. We will need to compile our code with a Babel present. We will get to it next section.
  • Finally, let’s add the Paragraph element to the DOM.
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>My Todo List</title>
  <meta name="description" content="My Todo list">
  <meta name="author" content="YourName">
  <script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
  <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
</head>
<body>
  <div id="container"></div>
  <script>
    // querySelector is a DOM API method to retrieve DOM elements.
    // To select DOM element with id, a leading # must be added.
    const containerElm = document.querySelector('#container');
  
    // createElement creates a React element with 3 parameters.
    // 1. type of the element 2. props for the element, 3. children of the element.
    // This could be written is a cleaner form call JSX which we will get to later.
    const Paragraph = React.createElement('p', {}, 'Hello World React');
  
    // This renders a React element into a DOM element.
    // React element as the first parameter and a DOM element as second parameter.
    ReactDOM.render(Paragraph, containerElm);
  </script>
</body>
</html>
  • Refresh the page and your will see that we will have our Hello World React showing on the page.
  • Use your mouse and hover the Hello World text, right click on your mouse and select Inspect. (I am using Chrome)
  • You can see that a

    Hello World React

    has been create inside the container that we have selected. That container is the starting point of our React application.
  • Good job guys, we have completed the first section. In the next section, we will setup same webpage differently which what we will use for our todo list application.

1. Setting up the project

This section is mainly for setting up the project with npm and webpack. If you have your own way of setting up your code, feel free to skip this section and go straight to part two of this tutorial.

We will first set up our project structure. Next, we are going to set up our project as a npm module. Installing packages through npm is an easy way to re-use open source code in our own project. Finally, we going to bundle our project with Webpack. With it, we will also set up a development environment with hot-reloading. It re-bundles our project and refreshes our webpage every time we make a change in the code which will make our development a lot more efficient.

Webpack allows us to choose how we want to compile your code through loaders. As an example, we are going to use Babel as one of the loaders for webpack. It enables us to write the latest javascript and also JSX. If you followed this tutorial from the beginning, you might remember that we had to use React.createElement to create a React element but with Babel, It will help us to transform JSX to createElement under the hood which is one of many things that Babel can compile.

1.1 Project structure

There are many ways to design a project’s folder structure. I will show you guys a simple way which you use it as a reference for you future projects.

  • Our current setup after the first section looks like this:

    . ├── index.html

  • We are going to create folders for dist, src and components using the commands we learned in the first section.
  • run mkdir dist src src/component in the project’s root to create all the folders listed below.
  • run touch src/index.js to create the entry point of our application.
  • run ls to check if the folders are created in the correct locations.

    . ├── dist/ ├── src/ │ ├── components/ │ └── index.js ├── index.html

  • dist: Store files bundled by webpack
  • src: Most of our files will be in src.

    • components: React components live in here.
    • index.js: Entry file for webpack.
  • index.html: Our webpage.

1.2 package.json

  • Make sure that you have node and npm installed.

    • To install npm, run npm install npm@latest -g
    • For node, I am using a node version manager called nvm. I am using node version 10.15.3 for this project. nvm allow you to switch node versions easily.
    • Check it out here if you are interested: https://github.com/nvm-sh/nvm
  • Let’s initialise a package.json file inside our new todo folder by running npm init.
  • npm init will prompt you to enter:

    • package name:

      • The package of your project which is todo in our case
    • version:

      • The current version of our project. We could use the default which is 1.0.0
    • description:

      • A brief description for the project. It could used to help you to search for your project by running npm search
    • entry point (main):

      • This will be script that will be return will people are using our project as one of their dependencies. we will set it to dist/main.js.
    • test command (scripts):

      • let’s set it to npm run test
      • This is one of the many scripts that we would define in package.json for running commands on our packages that we have installed, more on this later.
    • git repository (repository):

      • This would be the link to our project on a git repo. We could skip this.
    • keywords:

      • I have this set to todo.
      • This has the same purpose as description, it can be used for searching using npm search
    • author:

      • Leave your name here! You are the author of this project.
    • license:

      • This defines the license which is project is on. We could just use the default ISC which is free software license. This means that it is free to used by everyone.
  • We are done initialising our package.json file! run ls on your terminal to check if there is a package.json has created. Use your favourite editor to open the project and inspect the content inside our newly created package.json. You could see that the information that we have given during the prompts of npm init is inside the file.

1.3 Setup Webpack

  • In the root of our project, run

    touch webpack.config.js .babelrc
    • These are configuration file for webpack and babel.
  • Run

    npm i -D webpack webpack-cli
    • -D option saves the packages as dev dependencies.
  • Run

    npm i -D @babel/core @babel/preset-react @babel/preset-env babel-loader
    • @babel/core is babel itself
    • @babel/preset-react and @babel/preset-env are presets for babel. present-react allow us to use JSX in our react code.
    • babel-loader is for webpack to use babel as a loader.
  • Run

    npm i -D html-webpack-plugin

    We will use this webpack plugin to generate our index.html for development.

  • Run

    npm i -D webpack-dev-server

    to install a development server for webpack which we will configure in the wepack config file.

  • Let’s set up the configuration files

webpack.config.js

// Build-in node.js module which provides utilities for working with file and directory paths.
const path = require('path');

// Webpack plugin for creation of html files 
const HtmlWebpackPlugin = require('html-webpack-plugin');

// This exports a config for webpack.
module.exports = {

  // It tells webpack that we are configuring only for devleopment.
  // Webpack will bundle our code differently if we are bundling for production.
  mode: 'development',

  // This is the entry point for webpack to start bundling.
  entry: path.resolve(__dirname, 'src', 'index.js'),

  // This is the location which webpack will export our bundle into.
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist'),
  },
  module: {

    // This is for setting up rules for webpack to read our code. We are teaching webpack our to read our code. We are using regex to tell webpack to read all the files ending with js or jsx with babel-loader while excluding anything from node_modules.
    rules: [
      {
        test: /\.(js|jsx)$/,
        exclude: /node_modules/,
        loader: "babel-loader",
      }
    ],
  },

  // This is for debugging purposes. Specifying inline-source-map would show us the original code when we want to debug instead the code has been compiled or transformed.
  devtool: 'inline-source-map',

  // We configure our webpack-dev-server here. We are telling the server to listen to any changes to ./dist which include changes to our bundle and our index.html file.
  devServer: {
    contentBase: './dist',
    hot: true,
    compress: true,
  },

  plugins: [
    // This is exporting a html file named index.html into the location we have define in output above. It uses our index.html in our root that we have created in the first section. It will insert a script that that will include our bundle/javascript file which we did it manually in the first section.
    new HtmlWebpackPlugin({
      filename: 'index.html',
      template: path.resolve(__dirname, 'index.html'),
    }),
  ]
};

.babelrc

{
  "presets": [
    // Latest javascript
    "@babel/preset-env",

    // React
    "@babel/preset-react",
  ]
}
  • Next, we need to make some changes to our initial index.html which be our template.
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>My Todo List</title>
  <meta name="description" content="My Todo list">
  <meta name="author" content="YourName">
  <script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
  <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
</head>
<body>
  <div id="container"></div>
  <script>
    // querySelector is a document method to retrieve dom elements.
    // To select dom element with id, a leading # must be added.
    const containerElm = document.querySelector('#container');
  
    // createElement creates a React element with 3 parameters.
    // 1. type of the element 2. props for the element, 3. children of the element.
    // This could be written is a cleaner form call JSX which we will get to later.
    const Paragraph = React.createElement('p', {}, 'Hello World');
  
    // This renders a React element into a DOM element.
    // React element as the first parameter and a DOM element as second parameter.
    ReactDOM.render(Paragraph, containerElm);
  </script>
</body>
</html>
  • we are removing the React bundles as we are going to install them through npm and webpack is going to bundle them into a single file call main.js which then it will be injected by the HtmlWebpackPlugin into our index.html.
  • Let’s try to bundle our code with webpack!
  • First, let’s add a command in package.json to run trigger our bundling and development server.

    • paste

      "start": "webpack && webpack-dev-server"

      into scripts in package.json.

  • On your terminal, run npm run start and open the link http://localhost:8080/ to see if the development sever is running fine.
  • The server is serving the index.html that we have created in dist. Have a look inside the dist folder and you will see a main.js file and a index.html.
  • Open index.html and you will see that it’s similar to our index.html in our root except that the webpack plugin has insert main.js as a script in the file.

1.3 Install React

  • Let’s install react, run

    npm i react@^16.8.6 react-dom@^16.8.6

    in your todo project.

    • npm i is a short cut for npm install
    • We are installing react and react-dom, which we have also specified that we want version 16.8.
    • The caret (^) tells npm install that if there is a higher minor and/or patch version (number after the first dot and the number after the second dot respectively), it would install the latest minor and/or patch version packages instead.
    • For example, installing with ^16.8.6 would install automatically updates the packages to versions >= 16.8.6 and < 17.0.0.
    • Most all the projects are following a versioning called semver, short for semantic versioning. Read more about it here: https://semver.org/

1.4 Hello World

Finally, we have successfully setup our project. Let’s try print hello world using React to call end for this section.

  • Use your editor to open src/index.js and let’s write some code!
import React from 'react';
import ReactDOM from 'react-dom';

const HelloWord = () => (
  <p>Hello World React</p>
);

ReactDOM.render(<HelloWord />, document.querySelector('#container'));

If you have been following from the start, you might notice that the code that we have written is very similar to the ones we did. If you have your dev server running, go to http://localhost:8080/ to check out your great work!

Feel free to change the text inside the <p> tags to try out the fast hot reloading. Change the text and Save it in our editor, head over to the browser and you would see that your change has reflected in the browser without refreshing.

Great work guys! We have finished the second section of this step-by-step tutorial!


We are going to start building our todo list in the next part of this tutorial. I hope you have been enjoying the tutorial while learning something new. Please give me feedback on webdevdab@gmail.com. I am open to any constructive suggestions and comments. I am eager to improve on bringing you guys the best content. Thanks!