Getting Started with Create React App

Getting Started with Create React App

Learn how to scaffold a React Single-Page Application (SPA) with some sensible and opinionated defaults.

Learn how to scaffold a React Single-Page Application (SPA) with some sensible and opinionated defaults.

Introduction

You heard of <a href="https://github.com/facebook/create-react-app" target="_blank">create-react-app</a> before and, probably, you are even using this tool to scaffold your React apps. So, you may be wondering: "Why would I need to read this article and how does it help me?"

The answer to this question is simple: create-react-app is a great starting point but doesn't prepare the field to a real-world, production-ready SPA. As such, the goal of this article is to help you go through the steps needed to scaffold a React SPA that:

  • has a consistent code style (with the help of Prettier, a JavaScript formatter);
  • installs and configures some popular React libraries (like Redux and Redux Saga);
  • uses <a href="https://www.styled-components.com/docs/basics" target="_blank">styled-components</a> to help you manage the CSS of your React components;
  • configures React Bootstrap to give you a responsive, mobile-first application;
  • and that uses Auth0 to handle authentication easily.

After going through the steps here, you will have a SPA that:

  • is easy to extend;
  • multiple developers can contribute to (without ending with a spaghetti code);
  • has a nice user interface (based on one of the most popular React UI libraries out there);
  • can handle state and asynchronous tasks (like timeouts and AJAX requests) easily.
  • and that is secure.

If that sounds interesting, keep reading!

Prerequisites

To follow along with this article, you will need Node.js and NPM installed in your machine. If you don't have these tools, please, check this resource before continuing. On most installations, Node.js ships with NPM.

Besides that, you will have to have some basic knowledge of React. You don't need years of experience with it to follow the article along with, but you do have to understand its basic principles (components, JSX, etc.). If you are completely new to React, please, read this article first. After reading it, you will be able to read this one without struggling.

What You Will Build

In this article, you will build a very simple to-do list manager application. Your app will consume a to-do list from an external server and will allow users to add new to-do items to the local list. However, the app will not update this external server with the new items that users insert. The goal of this article is not to build the application, but to teach you how to put everything together so you can build awesome React apps that rely on a mature architecture.

Scaffolding the React SPA

The first thing you will do to scaffold your new React SPA is to use create-react-app. This tool is incredible and, just by issuing one command, you can put together a React app. So, open a terminal, move into the directory where you usually save your projects, and issue the following command:

npx create-react-app react-todo

This command will make NPM (or Yarn if you have that available) download the latest version of create-react-app and execute it to create your project under a new directory called react-todo. After running this command, move into the new directory (cd react-todo), and run npm start to see your new app. If everything works as expected, NPM will open <a href="http://localhost:3000" target="_blank">http://localhost:3000</a> for you in your default browser.

Note: Throughout this article, you will see npm commands everywhere. However, if you have Yarn installed in your machine, create-react-app will use it instead of NPM to scaffold your application. If that is the case, you will have to translate npm commands to yarn (e.g., instead of running npm start, you will need to execute yarn start), or you will have to remove the yarn-lock file and issue npm install to create the package-lock.json file for you. Feel free to choose whatever suits you better.

Installing and Configuring Prettier

All software developers have their own preferences when it comes to code style. Some prefer using semicolons, and some prefer leaving them out. Some prefer indenting code with tabs, and some prefer using two spaces. However, what is really important is that they don't mix these different styles on a single code base.

To easily accomplish that, you will use Prettier. Prettier, as explained by their website is an opinionated code formatter that you can use to help you keep the code style of your project consistent. If you configure Prettier properly, any software developer will be able to jump right into your project and start coding without worrying about code format. Then, when they save their modifications (or when they commit them), Prettier will make sure the code is formatted correctly. Sounds cool, right?

So, to use this tool, the first thing you will have to do is to stop the development server (by hitting Ctrl + C on the terminal). Then, you will have to issue the following command:

npm install husky lint-staged prettier

This will make NPM install three libraries:

  • husky and lint-staged: Together, these libraries will allow you to register an NPM script as a githook (this way Prettier will run right before the developer commits a new code).
  • prettier: This is the JavaScript formatter you want to use.

After installing these libraries, add the following properties to the package.json file:

// ./package.json

"husky": {
  "hooks": {
    "pre-commit": "lint-staged"
  }
},
"lint-staged": {
  "src/**/*.{js,jsx,ts,tsx,json,css,scss,md}": [
    "prettier --single-quote --write",
    "git add"
  ]
},
"prettier": {
  "singleQuote": true
}

The first property, husky, will make lint-staged run on Git's pre-commit phase. The second property, lint-staged, indicates what exactly NPM must run on this phase. The third property, prettier, changes the default configuration of Prettier to use <a href="https://prettier.io/docs/en/options.html#quotes" target="_blank">singleQuote</a> instead of double quotes.

With that in place, you might also be interested in integrating Prettier into your IDE. For that, you can check this resource. There, you will find that the community has built Prettier plugins for the most popular text editors and IDEs out there (e.g., WebStorm and VSCode)

For example, if you are using WebStorm, you will have to install this plugin. Then, after installing it, you can use the Reformat with Prettier action (Alt + Shift + Cmd + P on macOS or Alt + Shift + Ctrl + P on Windows and Linux) to format the selected code, a file, or a whole directory. Also, you might be interested in adding a WebStorm File Watcher to executes the Reformat with Prettier action on file modifications. If you are interested in this, please, check this resource.

Installing and Configuring React Bootstrap

After configuring Prettier into your project, the next thing you can do is to install and configure React Bootstrap. This library is a specialization of the Bootstrap toolkit. As Bootstrap depends on jQuery to run some components, the React community decided that it would be a good idea to remove this dependency and rebuild Bootstrap to integrate with React tightly. That's how React Bootstrap was born.

So, to install this library, issue the following command from the terminal:

npm install react-bootstrap bootstrap

After that, open the ./public/index.html file and, right after the title DOM element, import Bootstrap's CSS file:

<!-- ./public/index.html -->
<!DOCTYPE html>
<html lang="en">
  <head>
    <!-- ... title and other elements ... -->
    <link
      rel="stylesheet"
      href="https://maxcdn.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css"
      integrity="sha384-GJzZqFGwb1QTTN6wy59ffF1BuGJpLSa9DkKMp0DgiMDm4iYMj70gZWKYbI706tWS"
      crossorigin="anonymous"
    />
  </head>
  <!-- ... body ... -->
</html>

As explained on the official React Bootstrap documentation:

This library doesn't depend on a specific version of Bootstrap. As such, the library doesn't ship with any CSS file on it. However, some stylesheet is required to use these components. How and which Bootstrap styles you include is up to you, but the simplest way is to include the latest styles from the CDN. - React Bootstrap Introduction
Now, to check if the configuration is working, open the ./src/App.js file and replace its code with this:

// ./src/App.js

import React, { Component } from 'react';
import Container from 'react-bootstrap/Container';
import Button from 'react-bootstrap/Button';
import Col from 'react-bootstrap/Col';
import Row from 'react-bootstrap/Row';

class App extends Component {
  render() {
    return (
      <Container>
        <Row className="row">
          <Col xs={12}>
            <h1>My New React Bootstrap SPA</h1>
            <Button>Look, I'm a button!</Button>
          </Col>
        </Row>
      </Container>
    );
  }
}

export default App;

Then, back in your terminal, issue the following command to open your app in a web browser:

npm start

If everything works as expected, you will be able to see a page with a header (h1) and a Button that use Bootstrap's CSS rules.

Note: You are not using two files anymore: ./src/App.css and ./src/logo.svg. As such, feel free to delete them.## Installing PropTypes

As a React developer you probably already know what PropTypes is, but if you don't, here is the definition from React's documentation:

PropTypes exports a range of validators that can be used to make sure the data you (your React components) receive is valid. - Typechecking With PropTypes
That is, PropTypes allows you to add some type checking capabilities to your project with ease. For example, if you have a component that outputs a (required) message, you can add type checking with PropTypes like so:

import React from 'react';
import PropTypes from 'prop-types';

const Header = ({ description }) => <h1>{description}</h1>;

Header.propTypes = {
  description: PropTypes.string.isRequired
};

After that, whenever you use the Header component without passing a description to it, PropTypes will show a warning message in the JavaScript console. Note that this tool is there to help you in the development process. Also, for performance reasons, React only checks PropTypes in development mode.

So, before proceeding to more advanced topics, stop the development server (Ctrl + C) and issue the following command to install PropTypes:

npm install --save prop-types

Installing Redux and Integrating It with React

Next, you will install and integrate Redux in your React app. Redux, for those who don't know, is the most popular state management library among React developers. Redux itself is not tied to React but, most of the time, developers use them together.

If you don't know how Redux works, don't worry, you can still follow along with this article. In the end, you can read this practical tutorial on Redux to learn more about this library.
To integrate Redux with your React app, you will have to install two libraries:

npm install --save redux react-redux

The first one, <a href="https://github.com/reduxjs/redux" target="_blank">redux</a>, is Redux itself and the second one, <a href="https://github.com/reduxjs/react-redux" target="_blank">react-redux</a>, is a library that offers React bindings for Redux.

As you will build a simple to-do application in this article, the next thing you can do is to define the Redux actions that your app will handle. To do this, create a new directory called actions inside the src directory, then create a file called index.js inside it with the following code:

// ./actions/index.js

export const ADD_TODO = 'ADD_TODO';

export function addToDo(title) {
  return {
    type: ADD_TODO,
    toDoItem: {
      _id: (new Date().getTime()).toString(),
      title
    }
  };
}

Here you are defining that, for now, your app will handle a single type of action: ADD_TODO. Actions of this type, as you can see, will carry a toDoItem object with two properties: an id and a title.

After defining the action type your app will handle, you can create a Redux reducer to process actions. In this case, you will create a directory called reducers (again inside the src directory), and you will create a file called index.js inside it with this code:

// ./reducers/index.js

import { ADD_TODO } from '../actions';

const initialState = {
  toDoList: []
};

export default function toDoApp(state = initialState, action) {
  switch (action.type) {
    case ADD_TODO:
      let newToDoList = [
        ...state.toDoList,
        {
          ...action.toDoItem
        }
      ];
      return {
        ...state,
        toDoList: newToDoList
      };
    default:
      return state;
  }
}

This file has two goals. The first one is to define the initialState state of your app (which is an empty toDoList). The second one is to define what the toDoApp will do when it receives an ADD_TODO action (which is to include the new to-do item to the toDoList).

With that in place, you can open the ./src/index.js file and replace its contents with this:

// ./src/index.js

import React from 'react';
import { render } from 'react-dom';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import toDoApp from './reducers';
import App from './App';

const store = createStore(toDoApp);

render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);

The new version of this file is using the createStore function (provided by redux) to create a single source of truth object about the state of the app (i.e., the store constant). Then, it uses this store to feed the app with state.

Integrating React Components with Redux

After defining these Redux elements (actions, reducers, and the store), the next thing you can do is to define the React components that will use these elements. First, you will create two new directories:

  • ./src/components: This is where you will create your Presentational Components (that is, components that are not aware of Redux).
  • ./src/containers: This is where you will create Container Components (that is, components that tightly integrate to Redux).

After that, you can create a file called AddToDo.js inside the ./src/containers directory with the following code:

// ./src/containers/AddToDo.js

import React from 'react';
import { connect } from 'react-redux';
import { addToDo } from '../actions';
import Button from 'react-bootstrap/Button';
import Form from 'react-bootstrap/Form';
import InputGroup from 'react-bootstrap/InputGroup';

let AddToDo = ({ dispatch }) => {
  let input;

  return (
    <Form
      onSubmit={e => {
        e.preventDefault();
        if (!input.value.trim()) {
          return;
        }
        dispatch(addToDo(input.value));
        input.value = '';
      }}
    >
      <Form.Group controlId="formBasicEmail">
        <InputGroup>
          <Form.Control
            type="text"
            placeholder="Enter an item"
            ref={node => {
              input = node;
            }}
          />
          <InputGroup.Append>
            <Button type="submit">Add To-Do</Button>
          </InputGroup.Append>
        </InputGroup>
      </Form.Group>
    </Form>
  );
};
AddToDo = connect()(AddToDo);

export default AddToDo;

This component will present a form to your users and will allow them to input (and submit) new to-do items. As you can see, when your users submit this form, the component will dispatch an action that the addToDo function creates. This is enough to feed your app with to-do items but is not enough to present the items to your users.

To be able to present the to-do items, you will create two Presentation Components: ToDo and ToDoList. As their names state, the first one will render a single to-do item, while the second one will render a list of to-do items.

To define the ToDo component, create a new file called ToDo.js inside ./src/components and add the following code to it:

// ./src/components/ToDo.js

import React from 'react';
import PropTypes from 'prop-types';
import ListGroup from 'react-bootstrap/ListGroup';

const ToDo = ({ title }) => <ListGroup.Item>{title}</ListGroup.Item>;

ToDo.propTypes = {
  title: PropTypes.string.isRequired
};

export default ToDo;

This component will receive the description of the to-do item in question and will use the ListGroup.Item Bootstrap component to render the item.

Now, to define the ToDoList component, create a new file called ToDoList.js inside ./src/components and add the following code to it:

// ./src/components/ToDoList.js

import React from 'react';
import PropTypes from 'prop-types';
import ListGroup from 'react-bootstrap/ListGroup';
import Jumbotron from 'react-bootstrap/Jumbotron';
import ToDo from './ToDo';

const ToDoList = ({ toDoList }) => (
  <Jumbotron>
    <ListGroup>
      {toDoList.map((toDo, index) => (
        <ToDo key={index} {...toDo} />
      ))}
    </ListGroup>
  </Jumbotron>
);

ToDoList.propTypes = {
  toDoList: PropTypes.arrayOf(
    PropTypes.shape({
      _id: PropTypes.string.isRequired,
      title: PropTypes.string.isRequired
    }).isRequired
  ).isRequired
};

export default ToDoList;

This component will receive the toDoList, iterate over it, and render (inside a Jumbotron Bootstrap component) a list of ToDo components.

After defining these two presentational components, you will have to map the state of the app to the props of the ToDoList component. To do this, create a file called ToDoListContainer.js inside the ./src/containers directory and add the following code to it:

// ./src/containers/ToDoListContainer.js

import { connect } from 'react-redux';
import ToDoList from '../components/ToDoList';

const mapStateToProps = state => {
  return {
    toDoList: state.toDoList
  };
};

const ToDoListContainer = connect(mapStateToProps)(ToDoList);

export default ToDoListContainer;

This will make sure Redux maps the toDoList object available on its store (the state object on the source code above) to the toDoList property that the ToDoList presentational component uses.

With that in place, the last thing you will have to do is to make the App component use both Redux containers. So, open the ./src/App.js file and replace its code with this:

// ./src/App.js

import React, { Component } from 'react';
import Container from 'react-bootstrap/Container';
import Col from 'react-bootstrap/Col';
import Row from 'react-bootstrap/Row';

import AddToDo from './containers/AddToDo';
import ToDoListContainer from './containers/ToDoListContainer';

class App extends Component {
  render() {
    return (
      <Container>
        <Row className="row">
          <Col xs={12}>
            <h1>To Do List</h1>
            <AddToDo />
            <ToDoListContainer />
          </Col>
        </Row>
      </Container>
    );
  }
}

export default App;

Now, to see Redux in action, rerun npm start from the terminal. If everything works as expected, you will see your new to-do app up and running in your browser in a few seconds. There, you will be able to use the form to insert new to-do items.

Managing Side Effects on React with Redux Saga

Cool, you now have an application that can rely on a single source of truth when it comes to state management. However, one big gap of Redux is that this library does not handle well side effects (like those that AJAX requests provoke). To be able to handle this kind of side effect, you can use Redux Saga.

The goal of this article is not to teach everything about Redux Saga. For that, you can check this tutorial. However, even if you are not acquainted with this tool, you can still follow the instructions here to put the whole thing together. Then, when you finish reading this article, you can dive into this useful (and excellent) topic.

For starters, to install Redux Saga, stop the development server (Ctrl + C), then issue the following command:

npm i redux-saga

This will install the <a href="https://www.npmjs.com/package/redux-saga" target="_blank">redux-saga</a> dependency in your React project.

After installing it, you can open the ./src/actions/index.js file and update it as follows:

// ./src/actions/index.js

// ... ADD_TODO ...
export const LOAD_TODO_LIST = 'LOAD_TODO_LIST';
export const RENDER_TODO_LIST = 'RENDER_TODO_LIST';

// ... addToDo ...

export function loadToDoList() {
  return {
    type: LOAD_TODO_LIST
  };
}

The new version of this file is defining two new action types:

  • LOAD_TODO_LIST: This action type will make your React app load the to-do list from an external server.
  • RENDER_TODO_LIST: This action type will make your React app render the to-do list it just loaded.

Besides that, you are defining a function called loadToDoList to create an action with the LOAD_TODO_LIST type. In a few moments, you will make your React app use this function to dispatch an action of this type.

After defining these new action types, you can open the ./src/reducers/index.js file and update it as follows:

// ./src/reducers/index.js

// ... other imports ...

import { RENDER_TODO_LIST } from '../actions';

// ... initialState ...

export default function toDoApp(state = initialState, action) {
  switch (action.type) {
    case RENDER_TODO_LIST:
      return {
        ...state,
        toDoList: action.toDoList
      };
    // ... case ADD_TODO, and default ... :
  }
}

Here, you are adding a new case statement to the switch command that will handle RENDER_TODO_LIST actions. When your Redux receives an action with this type, it will read the toDoList payload and update the state of the app with the new list.

After this change, the next thing you will do is to create your first sagas. To do so, create a directory called sagas inside src, then create a file called index.js inside it with the following code:

// ./src/sagas/index.js

import { all, call, put, takeEvery } from 'redux-saga/effects';
import { LOAD_TODO_LIST, RENDER_TODO_LIST } from '../actions';

export function* fetchToDoList() {
  const endpoint = 'https://gist.githubusercontent.com/brunokrebs/f1cacbacd53be83940e1e85860b6c65b/raw/to-do-items.json';
  const response = yield call(fetch, endpoint);
  const data = yield response.json();
  yield put({ type: RENDER_TODO_LIST, toDoList: data });
}

export function* loadToDoList() {
  yield takeEvery(LOAD_TODO_LIST, fetchToDoList);
}

export default function* rootSaga() {
  yield all([loadToDoList()]);
}

Note: Sagas are implemented as Generator functions (function*) that yield objects to the redux-saga middleware. The yielded objects are a kind of instruction to be interpreted by the middleware. When a Promise is yielded to the middleware, the middleware will suspend the Saga until the Promise completes. - Redux Saga Beginner Tutorial
Here you can see that you are creating two sagas:

  • fetchToDoList: A saga that issues a request to a backend API (a static JSON file in this case) to fetch a toDoList.
  • loadToDoList: A saga that listens to LOAD_TODO_LIST actions to trigger the fetchToDoList saga.

When the fetchToDoList saga finishes loading the data from the API, it dispatches (through the put function) a RENDER_TODO_LIST action with the new list of to-do items. Then, the new version of your reducer captures this action and updates the state of the app accordingly.

After creating your sagas, the last thing you will have to do is to make your app dispatch a LOAD_TODO_LIST action right after loading on users' browsers. To achieve this, open the ./src/index.js file and replace its code with this:

// ./src/index.js

import React from 'react';
import { render } from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import createSagaMiddleware from 'redux-saga';

import App from './App';
import { loadToDoList } from './actions';
import toDoApp from './reducers';
import rootSaga from './sagas';

const sagaMiddleware = createSagaMiddleware();

const store = createStore(toDoApp, applyMiddleware(sagaMiddleware));

sagaMiddleware.run(rootSaga);

store.dispatch(loadToDoList());

render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);

Here, you are creating a sagaMiddleware to add to your app's store and you are making your app use the loadToDoList action creator to dispatch an action.

After this change, you can rerun your development server:

npm start

If you get everything right, you will see that your React app now loads two to-do items from the remote server: one to remind you to "buy pizza" and another one to remind you to "watch Netflix".

Handling Multiple Routes With React Router

Right now, your app is capable of:

  • rendering a nice user interface (with the help of React Bootstrap);
  • managing a single source of truth for its state (with the help of Redux);
  • and managing side effects that things like async HTTP requests cause (with the help of Redux Saga).

What you need now is to prepare your app to handle multiple routes. For that, you can use React Router, a declarative routing library for React.

To install this library, stop the development server (Ctrl + C), then run the following command:

npm i react-router-dom

After that, you have to import the BrowserRouter component and nest your App inside it. So, open the ./src/index.js file and update it as follows:

// ./src/index.js

// ... other imports ...
import { BrowserRouter } from 'react-router-dom';

// ... saga and redux config ...

render(
  <Provider store={store}>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </Provider>,
  document.getElementById('root')
);

Then, before adding any routes to your app, you will create a Navigation component that will allow users to navigate between different routes. So, create a file called Navigation.js inside ./src/components and add the following code to it:

// ./src/components/Navigation.js

import React from 'react';
import { Link } from 'react-router-dom';

export default () => (
  <div>
    <Link className="btn btn-primary" to="/">
      To-Do List
    </Link>
    <Link className="btn btn-secondary" to="/new-item">
      + Add New
    </Link>
  </div>
);

As you can see, this component creates two instances of Link: one that allows users to navigate to your home page (i.e., /) and one that allows them to navigate to a route where they will insert to-do items (/new-item). For demonstration purposes, you will split the form from the to-do list.

Now, what you need to do is to use the Navigation component in your App and define the two routes. For that, open the ./src/App.js file and update it as follows:

// ./src/App.js

// ... other imports ...
import { Route } from 'react-router-dom';
import Navigation from './components/Navigation';

class App extends Component {
  render() {
    return (
      <Container>
        <Row className="row">
          <Col xs={12}>
            <h1>To Do List</h1>
            <Navigation />
            <Route exact path="/" component={ToDoListContainer} />
            <Route exact path="/new-item" component={AddToDo} />
          </Col>
        </Row>
      </Container>
    );
  }
}
export default App;

Here, you are using the Route component to configure your app to render the ToDoListContainer component when users navigate to your home page, and to render the AddToDo component when they navigate to /new-item.

With that in place, you can rerun your application (npm start), and see the navigation feature working in your browser.

Installing and Using Styled-Components

Your architecture is almost complete now. You have installed and configured some useful libraries that help you handle navigation, state, and the user interface. However, you haven't done anything related to facilitating the enhancement of this user interface. For example, what if you wanted to change the style of your buttons? Or if you want to add some margin between your Navigation component and the list of to-do items? You could, of course, write a simple CSS file and import it in your React app. But this is old school.

Instead, you are going to use <a href="https://www.styled-components.com/docs/basics" target="_blank">style-components</a>, a library that, among other benefits, allows you to adapt the styling of a component based on its props. To install this library, once more you will have to stop the server (Ctrl + C), then you will have to issue the following command:

npm i styled-components

Now, you can import styled-components in a file, and use it to change the style of any component or DOM element. For example, open the ./src/components/Navigation.js and replace its code with this:

// ./src/components/Navigation.js

import React from 'react';
import { Link } from 'react-router-dom';
import styled from 'styled-components';

const NavigationBar = styled.div`
  margin-bottom: 15px;
  background-color: lightgray;
`;

export default () => (
  <NavigationBar>
    <Link className="btn btn-primary" to="/">
      To-Do List
    </Link>
    <Link className="btn btn-secondary" to="/new-item">
      + Add New
    </Link>
  </NavigationBar>
);

In the new version of this file, you are using styled-components to create a component called NavigationBar that is a div with some CSS styles. More specifically, you are defining that this div will have 15px of margin on its bottom and that it will have a lightgray background. As you can see, you use the new NavigationBar component just like other components (or DOM elements).

That's it! With that in place, you can rerun your app (npm start), and check the new layout in your browser.

Securing Your React Application

Lastly, you will have to think about securing your application. For that, you will use Auth0. You can't go too far without a good identity management system backing you up. You could, of course, build your own solution but, besides having to implement everything from the ground up (user registration, email confirmation, password reset, etc.), you will never have a solution that is as trustworthy as Auth0.

Auth0, a global leader in Identity-as-a-Service (IDaaS), provides thousands of customers in every market sector with the only identity solution they need for their web, mobile, IoT, and internal applications. Its extensible platform seamlessly authenticates and secures more than 2.5 billion logins per month, making it loved by developers and trusted by global enterprises. The company's U.S. headquarters in Bellevue, WA, and additional offices in Buenos Aires, London, Tokyo, and Sydney, support its global customers that are located in 70+ countries.
If you don't have one yet, you will have to create a free Auth0 account now. After creating it, go to the Applications section of your Auth0 dashboard and click on the Create Application button. Then, fill the form as follows:

  • Application Name: "React App"
  • Application Type: "Single Page Web App"

When you click on the Create button, Auth0 will redirect you to the Quick Start tab of your new application. From there, head to the Settings tab and make two changes:

  1. Add <a href="http://localhost:3000/callback" target="_blank">http://localhost:3000/callback</a> to the Allowed Callback URLs field.
  2. Add <a href="http://localhost:3000/" target="_blank">http://localhost:3000/</a> to the Allowed Logout URLs.

For security reasons, after the login and logout processes, Auth0 will only redirect users to the URLs you register in these two fields.
After updating the configuration, scroll to the bottom of the page, and click Save Changes. For now, leave this page open.

Back in the terminal, stop the development server (Ctrl + C), and issue the following command:

npm i auth0-js

This will install Auth0's headless browser SDK in your app. After installing it, create a new file called Auth.js inside src and add the following code to it:

// ./src/Auth.js

import auth0 from 'auth0-js';

const auth0Client = new auth0.WebAuth({
  // the following three lines MUST be updated
  domain: '<YOUR_AUTH0_DOMAIN>',
  audience: 'https://<YOUR_AUTH0_DOMAIN>/userinfo',
  clientID: '<YOUR_AUTH0_CLIENT_ID>',
  redirectUri: 'http://localhost:3000/callback',
  responseType: 'id_token',
  scope: 'openid profile email'
});

export function handleAuthentication() {
  return new Promise((resolve, reject) => {
    auth0Client.parseHash((err, authResult) => {
      if (err) return reject(err);
      if (!authResult || !authResult.idToken) {
        return reject(err);
      }
      const idToken = authResult.idToken;
      const profile = authResult.idTokenPayload;
      // set the time that the id token will expire at
      const expiresAt = authResult.idTokenPayload.exp * 1000;
      resolve({
        authenticated: true,
        idToken,
        profile,
        expiresAt
      });
    });
  });
}

export function signIn() {
  auth0Client.authorize();
}

export function signOut() {
  auth0Client.logout({
    returnTo: 'http://localhost:3000',
    clientID: '<YOUR_AUTH0_CLIENT_ID>'
  });
}

Note: In the code above, you will have to replace <YOUR_AUTH0_DOMAIN> and <YOUR_AUTH0_CLIENT_ID> (they both appear twice in the code) with the Domain and Client ID properties of your new Auth0 Application. You can get these properties from the page that you left open.
This file creates an auth0Client object with your Auth0 configuration and uses it to expose three functions:

  • handleAuthentication: You will call this function right after Auth0 redirects your users back to your app. At this moment, the function will fetch their idToken and profile (a.k.a., idTokenPayload) and send this information to whatever is listening to the promise that it returns.
  • signIn and signOut: These functions, as their names state, will initiate the login and logout processes.

After defining them, you will create two Redux actions that your app will need to interact with these functions. For that, open the ./src/actions/index.js file and update it as follows:

// ./src/actions/index.js

// ... other constants ...
export const USER_PROFILE_LOADED = 'USER_PROFILE_LOADED';
export const HANDLE_AUTHENTICATION_CALLBACK = 'HANDLE_AUTHENTICATION_CALLBACK';

// ... addToDo and loadToDoList ...

export function handleAuthenticationCallback() {
  return {
    type: HANDLE_AUTHENTICATION_CALLBACK
  };
}

Next, you will create a component that handles the authentication callback. So, create a file called Callback.js inside src/containers/ and add the following code to it:

// ./src/containers/Callback.js

import React from 'react';
import { connect } from 'react-redux';
import { Redirect } from 'react-router';
import { handleAuthenticationCallback } from '../actions';

const mapStateToProps = state => {
  return {
    user: state.user
  };
};

let Callback = ({ dispatch, user }) => {
  if (user) return <Redirect to="/" />;
  dispatch(handleAuthenticationCallback());

  return <div className="text-center">Loading user profile.</div>;
};
Callback = connect(mapStateToProps)(Callback);

export default Callback;

As you can see, when your app renders this component, it will check whether there is a user object available in the store or not (the component connects to Redux). If there is no user, it will use the handleAuthenticationCallback action creator to dispatch the HANDLE_AUTHENTICATION_CALLBACK action. If there is a user, it will redirect them to your home page.

At this moment you have the Redux actions, the code (that Auth.js provides), and the Callback component necessary to handle the callback process. What you need now is to open the ./src/sagas/index.js file and update it as follows:

// ./src/sagas/index.js

// ... other imports ...
import { takeLatest } from 'redux-saga/effects';
import { HANDLE_AUTHENTICATION_CALLBACK, USER_PROFILE_LOADED } from '../actions';
import { handleAuthentication } from '../Auth';

// ... fetchToDoList and loadToDoList ...

export function* parseHash() {
  const user = yield call(handleAuthentication);
  yield put({ type: USER_PROFILE_LOADED, user });
}

export function* handleAuthenticationCallback() {
  yield takeLatest(HANDLE_AUTHENTICATION_CALLBACK, parseHash);
}

// replace the current rootSaga generator
export default function* rootSaga() {
  yield all([loadToDoList(), handleAuthenticationCallback()]);
}

Here you are defining two new sagas. The first one, parseHash, will call and wait for the result of the handleAuthentication function. Then it will put a USER_PROFILE_LOADED action to let Redux know about the user who just signed in. The second one, handleAuthenticationCallback, is there to "listen" to HANDLE_AUTHENTICATION_CALLBACK actions so it can trigger the first saga. Lastly, you are updating the rootSaga to make the handleAuthenticationCallback saga run when the app starts.

After creating your new sagas, you can open the ./src/reducers/index.js file and update it as follows:

// ./src/reducers/index.js

// ... other imports ...
import { USER_PROFILE_LOADED } from '../actions';

// ... initialState ...

export default function toDoApp(state = initialState, action) {
  switch (action.type) {

    // ... RENDER_TODO_LIST and ADD_TODO ...

    case USER_PROFILE_LOADED:
      return {
        ...state,
        user: action.user
      };
    default:
      return state;
  }
}

This new version is adding a case statement to handle USER_PROFILE_LOADED actions. That is, when your saga informs Redux that the user logged in, the code in this statement will add the user object to your app's state.

These changes would suffice to integrate your app with Auth0. However, you are not consuming the user profile yet. To see the whole thing in action, you will make your Navigation component render information about the logged-in user. So, open the ./src/components/Navigation.js file and update it as follows:

// ./src/components/Navigation.js

// ... other imports ...
import { Fragment } from 'react';
import Button from 'react-bootstrap/Button';
import { signIn, signOut } from '../Auth';

// ... NavigationBar ...

const Profile = styled.span`
  margin-left: 15px;
`;

const ProfilePicture = styled.img`
  border-radius: 50%;
  max-width: 30px;
  margin-right: 5px;
`;

export default ({ user }) => (
  <NavigationBar>
    <Link className="btn btn-primary" to="/">
      To-Do List
    </Link>
    <Link className="btn btn-secondary" to="/new-item">
      + Add New
    </Link>
    {!user && <Button onClick={signIn}>Login</Button>}
    {user && (
      <Fragment>
        <Button onClick={signOut}>Logout</Button>
        <Profile>
          <ProfilePicture src={user.profile.picture} />
          {user.profile.email}
        </Profile>
      </Fragment>
    )}
  </NavigationBar>
);

With this change, you are making the navigation bar aware of the state of the user. If there is a logged-in user, then the app will show a logout button, the user profile picture, and their email address. If the user is not logged-in, the app will show a login button.

Before wrapping things up, you still need to feed the new version of your Navigation component with the user. To do this, create a new file called NavigationContainer.js inside ./src/containers and add the following code to it:

// ./src/containers/NavigationContainer.js

import { connect } from 'react-redux';
import Navigation from '../components/Navigation';

const mapStateToProps = state => {
  return {
    user: state.user
  };
};

const NavigationContainer = connect(mapStateToProps)(Navigation);

export default NavigationContainer;

Lastly, you will need to update the App component to replace Navigation with NavigationContainer and to add a callback route (/callback). So, open the ./src/App.js file and update it as follows:

// ./src/App.js

// ... other imports ...
import Callback from './containers/Callback';
import NavigationContainer from './containers/NavigationContainer';

class App extends Component {
  render() {
    return (
      <Container>
        <Row className="row">
          <Col xs={12}>
            <h1>To Do List</h1>
            <NavigationContainer />
            <Route exact path="/" component={ToDoListContainer} />
            <Route exact path="/new-item" component={AddToDo} />
            <Route exact path="/callback" component={Callback} />
          </Col>
        </Row>
      </Container>
    );
  }
}

export default App;

After this last change, if you rerun your application (npm start), you will be able to log in and log out from it with the help of Auth0. Easy, right?

Recap

In this article, you learned how to create a robust architecture that will help you scale your next React application. You started by using create-react-app to generate a simple app, then you went through a few different steps to install and configure libraries that will help you:

  • make your code style consistent (Prettier);
  • make your UI look good (React Bootstrap);
  • perform some type checkings (PropTypes);
  • manage the state of the application (Redux);
  • manage side effects (Redux Saga);
  • handle CSS with ease (Styled-Components);
  • and handle authentication (Auth0).

After configuring these libraries, you can rest assured that your next React application will rely on a mature and battle-tested architecture that can grow indefinitely.

JavaScript developers should you be using Web Workers?

JavaScript developers should you be using Web Workers?

Do you think JavaScript developers should be making more use of Web Workers to shift execution off of the main thread?

Originally published by David Gilbertson at https://medium.com

So, Web Workers. Those wonderful little critters that allow us to execute JavaScript off the main thread.

Also known as “no, you’re thinking of Service Workers”.

Photo by Caleb Jones on Unsplash

Before I get into the meat of the article, please sit for a lesson in how computers work:

Understood? Good.

For the red/green colourblind, let me explain. While a CPU is doing one thing, it can’t be doing another thing, which means you can’t sort a big array while a user scrolls the screen.

This is bad, if you have a big array and users with fingers.

Enter, Web Workers. These split open the atomic concept of a ‘CPU’ and allow us to think in terms of threads. We can use one thread to handle user-facing work like touch events and rendering the UI, and different threads to carry out all other work.

Check that out, the main thread is green the whole way through, ready to receive and respond to the gentle caress of a user.

You’re excited (I can tell), if we only have UI code on the main thread and all other code can go in a worker, things are going to be amazing (said the way Oprah would say it).

But cool your jets for just a moment, because websites are mostly about the UI — it’s why we have screens. And a lot of a user’s interactions with your site will be tapping on the screen, waiting for a response, reading, tapping, looking, reading, and so on.

So we can’t just say “here’s some JS that takes 20ms to run, chuck it on a thread”, we must think about where that execution time exists in the user’s world of tap, read, look, read, tap…

I like to boil this down to one specific question:

Is the user waiting anyway?

Imagine we have created some sort of git-repository-hosting website that shows all sorts of things about a repository. We have a cool feature called ‘issues’. A user can even click an ‘issues’ tab in our website to see a list of all issues relating to the repository. Groundbreaking!

When our users click this issues tab, the site is going to fetch the issue data, process it in some way — perhaps sort, or format dates, or work out which icon to show — then render the UI.

Inside the user’s computer, that’ll look exactly like this.

Look at that processing stage, locking up the main thread even though it has nothing to do with the UI! That’s terrible, in theory.

But think about what the human is actually doing at this point. They’re waiting for the common trio of network/process/render; just sittin’ around with less to do than the Bolivian Navy.

Because we care about our users, we show a loading indicator to let them know we’ve received their request and are working on it — putting the human in a ‘waiting’ state. Let’s add that to the diagram.

Now that we have a human in the picture, we can mix in a Web Worker and think about the impact it will have on their life:

Hmmm.

First thing to note is that we’re not doing anything in parallel. We need the data from the network before we process it, and we need to process the data before we can render the UI. The elapsed time doesn’t change.

(BTW, the time involved in moving data to a Web Worker and back is negligible: 1ms per 100 KB is a decent rule of thumb.)

So we can move work off the main thread and have a page that is responsive during that time, but to what end? If our user is sitting there looking at a spinner for 600ms, have we enriched their experience by having a responsive screen for the middle third?

No.

I’ve fudged these diagrams a little bit to make them the gorgeous specimens of graphic design that they are, but they’re not really to scale.

When responding to a user request, you’ll find that the network and DOM-manipulating part of any given task take much, much longer than the pure-JS data processing part.

I saw an article recently making the case that updating a Redux store was a good candidate for Web Workers because it’s not UI work (and non-UI work doesn’t belong on the main thread).

Chucking the data processing over to a worker thread sounds sensible, but the idea struck me as a little, umm, academic.

First, let’s split instances of ‘updating a store’ into two categories:

  1. Updating a store in response to a user interaction, then updating the UI in response to the data change
  2. Not that first one

If the first scenario, a user taps a button on the screen — perhaps to change the sort order of a list. The store updates, and this results in a re-rendering of the DOM (since that’s the point of a store).

Let me just delete one thing from the previous diagram:

In my experience, it is rare that the store-updating step goes beyond a few dozen milliseconds, and is generally followed by ten times that in DOM updating, layout, and paint. If I’ve got a site that’s taking longer than this, I’d be asking questions about why I have so much data in the browser and so much DOM, rather than on which thread I should do my processing.

So the question we’re faced with is the same one from above: the user tapped something on the screen, we’re going to work on that request for hopefully less than a second, why would we want to make the screen responsive during that time?

OK what about the second scenario, where a store update isn’t in response to a user interaction? Performing an auto-save, for example — there’s nothing more annoying than an app becoming unresponsive doing something you didn’t ask it to do.

Actually there’s heaps of things more annoying than that. Teens, for example.

Anyhoo, if you’re doing an auto-save and taking 100ms to process data client-side before sending it off to a server, then you should absolutely use a Web Worker.

In fact, any ‘background’ task that the user hasn’t asked for, or isn’t waiting for, is a good candidate for moving to a Web Worker.

The matter of value

Complexity is expensive, and implementing Web Workers ain’t cheap.

If you’re using a bundler — and you are — you’ll have a lot of reading to do, and probably npm packages to install. If you’ve got a create-react-app app, prepare to eject (and put aside two days twice a year to update 30 different packages when the next version of Babel/Redux/React/ESLint comes out).

Also, if you want to share anything fancier than plain data between a worker and the main thread you’ve got some more reading to do (comlink is your friend).

What I’m getting at is this: if the benefit is real, but minimal, then you’ve gotta ask if there’s something else you could spend a day or two on with a greater benefit to your users.

This thinking is true of everything, of course, but I’ve found that Web Workers have a particularly poor benefit-to-effort ratio.

Hey David, why you hate Web Workers so bad?

Good question.

This is a doweling jig:

I own a doweling jig. I love my doweling jig. If I need to drill a hole into the end of a piece of wood and ensure that it’s perfectly perpendicular to the surface, I use my doweling jig.

But I don’t use it to eat breakfast. For that I use a spoon.

Four years ago I was working on some fancy animations. They looked slick on a fast device, but janky on a slow one. So I wrote fireball-js, which executes a rudimentary performance benchmark on the user’s device and returns a score, allowing me to run my animations only on devices that would render them smoothly.

Where’s the best spot to run some CPU intensive code that the user didn’t request? On a different thread, of course. A Web Worker was the correct tool for the job.

Fast forward to 2019 and you’ll find me writing a routing algorithm for a mapping application. This requires parsing a big fat GeoJSON map into a collection of nodes and edges, to be used when a user asks for directions. The processing isn’t in response to a user request and the user isn’t waiting on it. And so, a Web Worker is the correct tool for the job.

It was only when doing this that it dawned on me: in the intervening quartet of years, I have seen exactly zero other instances where Web Workers would have improved the user experience.

Contrast this with a recent resurgence in Web Worker wonderment, and combine that contrast with the fact that I couldn’t think of anything else to write about, then concatenate that combined contrast with my contrarian character and you’ve got yourself a blog post telling you that maybe Web Workers are a teeny-tiny bit overhyped.

Thanks for reading

If you liked this post, share it with all of your programming buddies!

Follow us on Facebook | Twitter

Further reading

An Introduction to Web Workers

JavaScript Web Workers: A Beginner’s Guide

Using Web Workers to Real-time Processing

How to use Web Workers in Angular app

Using Web Workers with Angular CLI


Why ReactJS is better for Web Application Development?

Why ReactJS is better for Web Application Development?

Web Application Development is the point of contact for a business in today's digital era. It is important to choose the right platform for Web Application Development to build a high end Web

Web Application Development is essential for a business in today’s digital era. Finding the right platform for Web Application Development is important for building an effective Web Application that can enhance the overall customer engagement. Here’s what makes ReactJS a better option for building your next Web Application.