How to Create an Ecommerce Site with React

In this tutorial, we’ll look at how to build a very simple ecommerce web application with React. It won’t be the next Shopify, but hopefully it will serve as a fun way to demonstrate how well …


This content originally appeared on SitePoint and was authored by Deven Rathore

20 Essential React Tools for 2020

In this tutorial, we’ll look at how to build a very simple ecommerce web application with React. It won’t be the next Shopify, but hopefully it will serve as a fun way to demonstrate how well suited React is to building dynamic and engaging user interfaces.

The app will demonstrate a basic cart management system, as well as a simple method of handling user authentication. We’ll make use of React Context as an alternative to state management frameworks such as Redux or MobX, and we’ll create a fake back end using the json-server package.

Below is a screenshot of what we’ll be building:

The finished app

The code for this application is available on GitHub.

Prerequisites

This tutorial assumes you have a basic knowledge of JavaScript and React. If you are new to React, you might like to check out our beginner’s guide.

To build the application, you’ll need a recent version of Node installed on your PC. If this isn’t the case, then head over to the Node home page and download the correct binaries for your system. Alternatively, you might consider using a version manager to install Node. We have a tutorial on using a version manager here.

Node comes bundled with npm, a package manager for JavaScript, with which we’re going to install some of the libraries we’ll be using. You can learn more about using npm here.

You can check that both are installed correctly by issuing the following commands from the command line:

node -v
> 12.18.4

npm -v
> 6.14.8

With that done, let’s start off by creating a new React project with the Create React App tool. You can either install this globally, or use npx, like so:

npx create-react-app e-commerce

When this has finished, change into the newly created directory:

cd e-commerce

In this application, we’ll use React Router to handle the routing. To install this module, run:

npm install react-router-dom

We’ll also need json-server and json-server-auth to create our fake back end to handle authentication:

npm install json-server json-server-auth

We’ll need axios for making Ajax requests to our fake back end.

npm install axios

And we’ll need jwt-decode so that we can parse the JWT that our back end will respond with:

npm install jwt-decode

Finally, we’ll use the Bulma CSS framework to style this application. To install this, run the following command:

npm install bulma

Getting Started

First, we need to add the stylesheet to our application. To achieve this, we’ll add an import statement to include this file in the index.js file in the src folder. This will apply the style sheet across all the components in the application:

import "bulma/css/bulma.css";

Context Setup

As previously mentioned, we’ll be using React Context throughout our app. This is a relatively new addition to React and provides a way to pass data through the component tree without having to pass props down manually at every level.

If you’d like a refresher on using context in a React application, check out our tutorial “How to Replace Redux with React Hooks and the Context API”.

In complex applications where the need for context is usually necessary, there can be multiple contexts, with each having its own data and methods relating to the set of components that requires the data and methods. For example, there can be a ProductContext for handling the components which use product-related data, and another ProfileContext for handling data related to authentication and user data. However, for the sake of keeping things as simple as possible, we’ll use just one context instance.

In order to create the context, we create a Context.js file and a withContext.js files in our app’s src directory:

cd src
touch Context.js withContext.js

Then add the following to Context.js:

import React from "react";
const Context = React.createContext({});
export default Context;

This creates the context and initializes the context data to an empty object. Next, we need to create a component wrapper, which we’ll use to wrap components that use the context data and methods:

// src/withContext.js

import React from "react";
import Context from "./Context";

const withContext = WrappedComponent => {
  const WithHOC = props => {
    return (
      <Context.Consumer>
        {context => <WrappedComponent {...props} context={context} />}
      </Context.Consumer>
    );
  };

  return WithHOC;
};

export default withContext;

This might look a little complicated, but essentially all it does is make a higher-order component, which appends our context to a wrapped component’s props.

Breaking it down a little, we can see that the withContext function takes a React component as its parameter. It then returns a function that takes the component’s props as a parameter. Within the returned function, we’re wrapping the component in our context, then assigning it the context as a prop: context={context}. The {...props} bit ensures that the component retains any props that were passed to it in the first place.

All of this means that we can follow this pattern throughout our app:

import React from "react";
import withContext from "../withContext";

const Cart = props => {
  // We can now access Context as props.context
};

export default withContext(Cart);

Scaffolding Out the App

Now, let’s create a skeleton version of the components we’ll need for our app’s basic navigation to function properly. These are AddProducts, Cart, Login and ProductList, and we’re going to place them in a components directory inside of the src directory:

mkdir components
cd components
touch AddProduct.js Cart.js Login.js ProductList.js

In AddProduct.js add:

import React from "react";

export default function AddProduct() {
  return <>AddProduct</>
}

In Cart.js add:

import React from "react";

export default function Cart() {
  return <>Cart</>
}

In Login.js add:

import React from "react";

export default function Login() {
  return <>Login</>
}

And finally, in ProductList.js add:

import React from "react";

export default function ProductList() {
  return <>ProductList</>
}

Next, we need to set up up the App.js file. Here, we’ll be handling the application’s navigation as well as defining its data and methods to manage it.

First, let’s set up up the navigation. Change App.js as follows:

import React, { Component } from "react";
import { Switch, Route, Link, BrowserRouter as Router } from "react-router-dom";

import AddProduct from './components/AddProduct';
import Cart from './components/Cart';
import Login from './components/Login';
import ProductList from './components/ProductList';

import Context from "./Context";

export default class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      user: null,
      cart: {},
      products: []
    };
    this.routerRef = React.createRef();
  }

  render() {
    return (
      <Context.Provider
        value={{
          ...this.state,
          removeFromCart: this.removeFromCart,
          addToCart: this.addToCart,
          login: this.login,
          addProduct: this.addProduct,
          clearCart: this.clearCart,
          checkout: this.checkout
        }}
      >
        <Router ref={this.routerRef}>
        <div className="App">
          <nav
            className="navbar container"
            role="navigation"
            aria-label="main navigation"
          >
            <div className="navbar-brand">
              <b className="navbar-item is-size-4 ">ecommerce</b>
              <label
                role="button"
                class="navbar-burger burger"
                aria-label="menu"
                aria-expanded="false"
                data-target="navbarBasicExample"
                onClick={e => {
                  e.preventDefault();
                  this.setState({ showMenu: !this.state.showMenu });
                }}
              >
                <span aria-hidden="true"></span>
                <span aria-hidden="true"></span>
                <span aria-hidden="true"></span>
              </label>
            </div>
              <div className={`navbar-menu ${
                  this.state.showMenu ? "is-active" : ""
                }`}>
                <Link to="/products" className="navbar-item">
                  Products
                </Link>
                {this.state.user && this.state.user.accessLevel < 1 && (
                  <Link to="/add-product" className="navbar-item">
                    Add Product
                  </Link>
                )}
                <Link to="/cart" className="navbar-item">
                  Cart
                  <span
                    className="tag is-primary"
                    style={{ marginLeft: "5px" }}
                  >
                    { Object.keys(this.state.cart).length }
                  </span>
                </Link>
                {!this.state.user ? (
                  <Link to="/login" className="navbar-item">
                    Login
                  </Link>
                ) : (
                  <Link to="/" onClick={this.logout} className="navbar-item">
                    Logout
                  </Link>
                )}
              </div>
            </nav>
            <Switch>
              <Route exact path="/" component={ProductList} />
              <Route exact path="/login" component={Login} />
              <Route exact path="/cart" component={Cart} />
              <Route exact path="/add-product" component={AddProduct} />
              <Route exact path="/products" component={ProductList} />
            </Switch>
          </div>
        </Router>
      </Context.Provider>
    );
  }
}

Our App component will be responsible for initializing the application data and will also define methods to manipulate this data. First, we define the context data and methods using the Context.Provider component. The data and methods are passed as a property, value, on the Provider component to replace the object given on the context creation. (Note that the value can be of any data type.) We pass the state value and some methods, which we’ll define soon.

Next, we build our application navigation. To achieve this, we need to wrap our app with a Router component, which can either be BrowserRouter (like in our case) or HashRouter. Next, we define our application’s routes using the Switch and Route components. We also create the app’s navigation menu, with each link using the Link component provided in the React Router module. We also add a reference, routerRef, to the Router component to enable us to access the router from within the App component.

To test this out, head to the project root (for example, /files/jim/Desktop/e-commerce) and start the Create React App dev server using npm start. Once it has booted, your default browser should open and you should see the skeleton of our application. Be sure to click around and make sure all of the navigation works.

Spinning up a Fake Back End

In the next step, we’ll set up a fake back end to store our products and handle user authentication. As mentioned, for this we’ll use json-server to create a fake REST API and json-server-auth to add a simple JWT-based authentication flow to our app.

The way json-server works is that it reads in a JSON file from the file system and uses that to create an in-memory database with the corresponding endpoints to interact with it. Let’s create the JSON file now. In the route of your project, create a new backend folder and in that folder create a new db.json file:

mkdir backend
cd backend
touch db.json

Open up db.json and add the following content:

{
  "users": [
    {
      "email": "regular@example.com",
      "password": "$2a$10$2myKMolZJoH.q.cyXClQXufY1Mc7ETKdSaQQCC6Fgtbe0DCXRBELG",
      "id": 1
    },
    {
      "email": "admin@example.com",
      "password": "$2a$10$w8qB40MdYkMs3dgGGf0Pu.xxVOOzWdZ5/Nrkleo3Gqc88PF/OQhOG",
      "id": 2
    }
  ],
  "products": [
    {
      "id": "hdmdu0t80yjkfqselfc",
      "name": "shoes",
      "stock": 10,
      "price": 399.99,
      "shortDesc": "Nulla facilisi. Curabitur at lacus ac velit ornare lobortis.",
      "description": "Cras sagittis. Praesent nec nisl a purus blandit viverra. Ut leo. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Fusce a quam."
    },
    {
      "id": "3dc7fiyzlfmkfqseqam",
      "name": "bags",
      "stock": 20,
      "price": 299.99,
      "shortDesc": "Nulla facilisi. Curabitur at lacus ac velit ornare lobortis.",
      "description": "Cras sagittis. Praesent nec nisl a purus blandit viverra. Ut leo. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Fusce a quam."
    },
    {
      "id": "aoe8wvdxvrkfqsew67",
      "name": "shirts",
      "stock": 15,
      "price": 149.99,
      "shortDesc": "Nulla facilisi. Curabitur at lacus ac velit ornare lobortis.",
      "description": "Cras sagittis. Praesent nec nisl a purus blandit viverra. Ut leo. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Fusce a quam."
    },
    {
      "id": "bmfrurdkswtkfqsf15j",
      "name": "shorts",
      "stock": 5,
      "price": 109.99,
      "shortDesc": "Nulla facilisi. Curabitur at lacus ac velit ornare lobortis.",
      "description": "Cras sagittis. Praesent nec nisl a purus blandit viverra. Ut leo. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Fusce a quam."
    }
  ]
}

We’re creating two resources here — users and products. Looking at the users resource, you’ll notice that each user has an ID, an email address and a password. The password appears as a jumble of letters and numbers, as it’s encrypted using bcryptjs. It’s important that you don’t store passwords in plain text anywhere in your application.

That said, the plain text version of each password is simply “password” — without the quotes.

Now start up the server by issuing the following command from the root of the project:

./node_modules/.bin/json-server-auth ./backend/db.json --port 3001

This will start json-server on http://localhost:3001. Thanks to the json-server-auth middleware, the users resource will also give us a /login endpoint that we can use to simulate logging in to the app.

Let’s try it out using https://hoppscotch.io. Open that link in a new window, then change the method to POST and the URL to http://localhost:3001/login. Next, make sure the Raw input switch is set to on and enter the following as the Raw Request Body:

{
  "email": "regular@example.com",
  "password": "password"
}

Click Send and you should receive a response (further down the page) that looks like this:

{
  "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6InJlZ3VsYXJAZXhhbXBsZS5jb20iLCJpYXQiOjE2MDE1Mzk3NzEsImV4cCI6MTYwMTU0MzM3MSwic3ViIjoiMSJ9.RAFUYXxG2Z8W8zv5-4OHun8CmCKqi7IYqYAc4R7STBM"
}

That is a JSON Web Token, which is valid for an hour. In a normal app with a proper back end, you’d save this in the client, then send it to the server whenever you requested a protected resource. The server would validate the token it received and if everything checked out, it would respond with the data you requested.

This point is worth repeating. You need to validate any request for a protected resource on your server. This is because the code that runs in the client can potentially be reverse engineered and tampered with.

Here’s a link to the finished request on Hoppscotch. You just need to press Send.

If you’d like to find out more about using JSON Web Tokens with Node.js, please consult our tutorial.

Continue reading How to Create an Ecommerce Site with React on SitePoint.


This content originally appeared on SitePoint and was authored by Deven Rathore


Print Share Comment Cite Upload Translate Updates
APA

Deven Rathore | Sciencx (2020-10-14T04:00:23+00:00) How to Create an Ecommerce Site with React. Retrieved from https://www.scien.cx/2020/10/14/how-to-create-an-ecommerce-site-with-react/

MLA
" » How to Create an Ecommerce Site with React." Deven Rathore | Sciencx - Wednesday October 14, 2020, https://www.scien.cx/2020/10/14/how-to-create-an-ecommerce-site-with-react/
HARVARD
Deven Rathore | Sciencx Wednesday October 14, 2020 » How to Create an Ecommerce Site with React., viewed ,<https://www.scien.cx/2020/10/14/how-to-create-an-ecommerce-site-with-react/>
VANCOUVER
Deven Rathore | Sciencx - » How to Create an Ecommerce Site with React. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2020/10/14/how-to-create-an-ecommerce-site-with-react/
CHICAGO
" » How to Create an Ecommerce Site with React." Deven Rathore | Sciencx - Accessed . https://www.scien.cx/2020/10/14/how-to-create-an-ecommerce-site-with-react/
IEEE
" » How to Create an Ecommerce Site with React." Deven Rathore | Sciencx [Online]. Available: https://www.scien.cx/2020/10/14/how-to-create-an-ecommerce-site-with-react/. [Accessed: ]
rf:citation
» How to Create an Ecommerce Site with React | Deven Rathore | Sciencx | https://www.scien.cx/2020/10/14/how-to-create-an-ecommerce-site-with-react/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.