Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / React

Create a Basic Sales App using React

4.50/5 (3 votes)
1 Jan 2018CPOL6 min read 16.7K  
A step-by-step tutorial for building a basic sales application using React

React is a popular front-end technology for building apps and tools for the web and the mobile platform. In this tutorial, we will create a basic sales tool application that lets you create new orders, view existing in a tabular structure and delete them. You can build on the ideas covered in this tutorial and incorporate them into your projects.

Prerequisites

All the code for this tutorial is available in the codesandbox demo below. Alternatively, you can fork them from my GitHub repository.

The sales application that we’re building has a few dependencies -- namely, react-router and react-table. Although I've filled in all the relevant parts, an in-depth explanation of the working of these packages is beyond the scope of this tutorial.

Setting Up the React Environment

create-react-app allows you to jump-start your React development with zero hassle and zero configuration. Start a new project using create-react-and install the dependencies using yarn/npm.

$ create-react-app sales-tool

$ yarn add react-router react-router react-router-dom react-table

yarn start runs the application in the development mode.

Overview of the Sales Tool

It’s always recommended to have a rough sketch or a visual representation of the application we are about to build.

The sales tool application will have three components:

  1. App.js: The App component will be the entry point to the sales tool. It will have a button that lets you create new orders and a table that lists existing orders.
  2. CreateOrderForm.js - The CreateOrderForm component handles the logic for creating new orders.
  3. OrderTable.js - The OrderTable component lists the order data in an organised tabular structure.

Creating an Entry Point: App Component

The entire state of the application and the logic for handling the state resides inside the App component. The App will pass them down as props to CreateOrderForm and OrderTable which are presentational components.

Here is how I’ve initialized the state. The this.state.order stores the state of the particular order while the form is being filled in. The this.state.orderList is an array of orders that are submitted using the form.

JavaScript
class App extends Component {

  constructor() {
    super();

    this.state = {
      order: {
        id: '',
        name : '',
        email: '',
        address: '',
        phone: '',
        units: '',
      },
     orderList: [],
    
    this.initialOrder = this.state.order;
    }
  }
  ...
}

For managing the state, we need the following methods:

  1. handleChange(): This gets invoked when the value of the input control elements in the order form is changed. It accepts two parameters, the key and the value that needs to be changed.
  2. handleSubmit(): When the user clicks the submit button, this method is executed. The order object is pushed to the orderList array and the state of the order is cleared.
  3. handleDelete(): This method deals with the logic for deleting a particular order. It accepts a parameter which is the object to be deleted. The orderList array is filtered based on the order id and any instance of an order with that id is deleted.
  4. resetAll(): resetAll() is used to reset the orderList to an empty array.
JavaScript
handleChange(name, value) {
   this.setState(
     prevState => {
       return(
         {
           order: { ...prevState.order, [name]:value }
         }
       )
     }
   )
 }

 handleSubmit() {
   this.setState(
     prevState => {
       return(
       {
         orderList: [...prevState.orderList, prevState.order],
         order: this.initialOrder
       })
     }, () => {
       this.props.history.push('/');

     }
   )
 }

 handleDelete(itemToBeDeleted) {

   let updatedOrderList = this.state.orderList.filter(function(order)
                          { return order.id !== itemToBeDeleted.id });
   this.setState({
     orderList: updatedOrderList
   })
}


resetOrderList() {
   this.setState({
     orderList: []
   })
 }

That’s it!

Routing the Application

Next up, navigation. When the user navigates to ‘/’, they will see two buttons on top, and a table that displays all the orders. Clicking the Create New Order button would navigate the user to the path ‘/new’ that displays an Order Form.

Image 1

Let’s add the routes for this simple structure. You will have to import the API for routing from react-router-dom.

JavaScript
import  { Route, Switch, withRouter } from 'react-router-dom';

Update the export declaration of the App component as follows:

JavaScript
export default withRouter(App);

withRouter is a Higher-Order Component that adds extra props into your component. For instance, you can now access the history object via this.props.history. You can push a new path into the history using this.props.history.push or access the current location using this.props.history.location. Here’s how the render method looks like:

JavaScript
  render() {

    return(
      <div>
       { this.props.history.location.pathname === '/'? this.renderTopButtons() : null }
        <Switch>
          <Route exact path="/" render={ () => <OrderTable {...this.props} 
                    orders = { this.state.orderList } onDelete = {this.handleDelete} /> } />
          <Route path="/new" render = { () => <CreateOrderForm {...this.props} 
                    onChange = {this.handleChange} onSubmit = {this.handleSubmit} /> } />
        </Switch>
              
      </div>
      
    );
  }
}

The renderTopButton() method renders the buttons on top.

JavaScript
renderTopButtons() {
    return( 
      <div className = "container">
        <div className = "row col-md-8 offset-md-4   mt-4 mb-4">
          <button className = "btn btn-primary mx-2" 
           onClick = { this.props.history.push('/new'); }> Create New Order </button>
          <button className = "btn btn-danger mx-2" 
           onClick = { this.resetOrderList }> Delete All </button>
        </div>
      </div>)
  }

We’ve passed in the state data as props. In addition, we’ve added callbacks for the handler methods so that the child components can update the state.

Our work on the App component is complete.

React Forms: Form for Creating a New Order

Next, let’s fill in the CreateOrderForm component. It’s a functional component that displays a form. It uses the props to communicate with the parent App component when either the value of a form element changes or the submit button is clicked.

JavaScript
const CreateOrderForm = (props) => {
 /*  Omitted for brevity */
  return(
    <div>
        <br/>
        
        <h2> Create an Order </h2>
        <br/>
        <form onSubmit  = {handleSubmit} onChange= {handleChange} >

            <div>
              <input name="id" type="number" id="example-number-input" />
            </div>
        
            <div>
              <input name="name" type="text" id="example-text-input" />
            </div>
       
            <div>
              <input name="email" type="email" id="example-email-input" />
            </div>
     
            <div>
              <textarea name="address" cols="50" rows="3" type="address" />
            </div>
      
            <div>
              <input name="phone" type="tel" id="example-tel-input" />
            </div>
    
            <div>
             <input name="units" type="number" id="example-number-input" />
           </div>
       
           <div className="offset-md-4">
             <button type="submit"> Submit </button>
           </div>

      </form> 
    </div>
    )
}

export default CreateOrderForm;

The code above is a stripped down version of the actual CreateOrderForm component with the CSS styles removed. There are two important things to note here. First, the form element holds the event listener for onChange and onSubmit events and not the individual input elements.

HTML
<form onSubmit  = {handleSubmit} onChange= {handleChange} >

Second, each input control element should have a name attribute.

HTML
<input name="id" type="number" id="example-number-input" />

Now, all you need to do is define the handler methods handleSubmit() and handleChange() as follows:

const handleSubmit = (e) => {
   e.preventDefault();
   props.onSubmit();
 }

 const handleChange = (e) => {
   const inputName = e.target.name;
   const inputValue = e.target.value;

   props.onChange(inputName,inputValue);
 }

Displaying the Order Data

The OrderTable component is responsible for displaying the sales order data. If you recall, we passed down the state of the orderList and a callback for handleDelete method as props.

JavaScript
<OrderTable {...this.props} orders = { this.state.orderList } onDelete = {this.handleDelete} /> } />

React-table is the de-facto library for creating beautiful tables with ease in React. Since we have already installed the package, all we need to do is import the API and the stylesheet.

JavaScript
import React from 'react';
import ReactTable from 'react-table';
import 'react-table/react-table.css'

const OrderTable = ({orders, onDelete}) => {

  }

export default OrderTable;

Creating a React table is easy. You have to pass the data and the columns as props.

JavaScript
<ReactTable data={data} columns={columns} />

We already have the data to be displayed inside the orders object.

JavaScript
const data = orders;

For the column, create a column object like the one below:

JavaScript
const columns = [{

    Header: 'id',
    accessor: 'id',
    maxWidth: 100
  }, {
    Header: 'Name',
    accessor: 'name',

  }, {
  
    Header: 'Email',
    accessor: 'email' 
  }, {
    Header: 'Address', 
    accessor: 'address',
    width: 400
  },  {
    Header: 'Telephone', 
    accessor: 'phone'
  },  {
    Header: 'Units', 
    accessor: 'units',
    maxWidth: 150
  }]

You can declare the name that you want to appear as the column title in the Header field. The value of the accessor field corresponds to a key in the data object. Columns can be further customized by declaring the column width, height, etc. You can read more about it in the official documentation.

Here is how the final version of the ReactTable component declaration looks like:

JavaScript
<ReactTable data={data} columns={columns} defaultPageSize={5} className="-striped -highlight"  />

We now have a working, but basic sales tool.

Deleting Individual Orders

What if we needed an additional column with a delete button which will delete that particular order entry? With React table, this isn’t hard to accomplish. Add an extra column field with the following values:

JavaScript
{
  Header: 'Delete',
  accessor: 'delete',
  Cell: (row) =>( <img src="/img/delete.png" onClick={ () => { handleDelete(row.original)}}  />),
  maxWidth: 150
}

The Cell renderer receives a function. The function renders a delete button with an onClick event listener for handling the deletion logic. In the example above, row is a prop and row.original has the original row data.

JavaScript
const handleDelete = (item) => {
    onDelete(item);
  }

We’re all done. We now have a fully functional sales tool that you can use for creating, tracking and deleting orders.

Final Demo

Here is the final demo of the application that we’ve built. You can see the live demo at CodeSandbox.

Summary

Although the sales tool application might appear trivial, we have covered a lot of ground building it. We learned the basics of React, and two popular third-party packages in React -- React router and React table. Furthermore, we’ve created an application that handles most of the CRUD operations. I hope that you’ve enjoyed this tutorial. Share your thoughts in the comments.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)