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:
- 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. - CreateOrderForm.js - The
CreateOrderForm
component handles the logic for creating new orders. - 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.
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:
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. 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. 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. resetAll()
: resetAll()
is used to reset the orderList
to an empty array.
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.
Let’s add the routes for this simple structure. You will have to import the API for routing from react-router-dom
.
import { Route, Switch, withRouter } from 'react-router-dom';
Update the export declaration of the App
component as follows:
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:
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.
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.
const CreateOrderForm = (props) => {
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.
<form onSubmit = {handleSubmit} onChange= {handleChange} >
Second, each input control element should have a name
attribute.
<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
.
<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.
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
.
<ReactTable data={data} columns={columns} />
We already have the data to be displayed inside the orders
object.
const data = orders;
For the column, create a column object like the one below:
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:
<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:
{
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.
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.