How to Create an Ecommerce Site with React

How to Create an Ecommerce Site with React

Learn how to build a very simple ecommerce web application with React, using React Context for state management, and adding a basic method for handling authentication and cart management.

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 });
                }}
              >



              </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.

react javascript web-development programming developer

Bootstrap 5 Complete Course with Examples

Bootstrap 5 Tutorial - Bootstrap 5 Crash Course for Beginners

Nest.JS Tutorial for Beginners

Hello Vue 3: A First Look at Vue 3 and the Composition API

Building a simple Applications with Vue 3

Deno Crash Course: Explore Deno and Create a full REST API with Deno

How to Build a Real-time Chat App with Deno and WebSockets

Convert HTML to Markdown Online

HTML entity encoder decoder Online

How native is React Native? | React Native vs Native App Development

Article covers: How native is react native?, React Native vs (Ionic, Cordova), Similarities and difference between React Native and Native App Development.

How To Write Better Code As A Web Developer - React

Look at three different React code examples from a beginner, intermediate, and advanced web developer. How senior developers think. How to use React state properly. How to use React useEffect properly. What to think about when programming. The differences between senior and junior developers

How to Become A React JavaScript Developer 🚀

Today Qazi & Sonny will be showing you How To Become a React JavaScript Developer 🚀👨‍💻

Hire Dedicated React Native Developer

Have you ever thought of having your own app that runs smoothly over multiple platforms? React Native is an open-source cross-platform mobile application framework which is a great option to create mobile apps for both Android and iOS. **[Hire...

Top 10 Web Development Trends in 2020 | Web Development Skills

Top 10 Web Development Trends in 2020 will provide you with a detailed list of the trends which are currently being noticed. Upskilling to these trends will help you in landing onto better jobs in 2020-2021.