Sometime back I came across a library called React Bootstrap Table. This helps you to build the table with loads of features like Pagination, Filtering, Sorting, Export to CSV and many more. And even it allows you to customise as per your need. I’ve explored various grid / table component libraries to use, but many came with difficulty to either learning or implementing or lack of expected feature. So I’ve got settled with this library and moreover it is actively maintained.
You can download the sample from here. This has the instructions on how to setup and run the demo.
Before writing our component, we need some data to populate our table. I used Mockaroo to generate the mock data. The mock data contains id, productName, price, manufacturedDate, expiryDate elements with 100 rows. I would like to show 10 rows in table with 10 paginated links. This way at any point of time, user’s browser will only have 10 rows of data. For every pagination navigation, there will be a fetch call triggered.
To ease certain things, I use mock api instead of real api, which will return the data when queried. Create a file called mockApi.js in src/api/mockApi.js.
import _ from 'underscore'
// Mock data generated from https://www.mockaroo.com/
const mockData = [
{
id: 1,
productName: 'pain reliever',
price: 14,
manufacturedDate: '2016-08-01',
expiryDate: '2016-07-11'
},
{
id: 2,
productName: 'Dorzolamide Hydrochloride and Timolol Maleate',
price: 100,
manufacturedDate: '2015-12-30',
expiryDate: '2016-05-29'
}
]
class ProductApi {
// Get the products by page number
static getProducts(page) {
return new Promise((resolve, reject) => {
// Just to simulate a delay
setTimeout(() => {
let products = {}
products.pageCount = 10
products.resultsCount = 100
products.productList = _.first(_.rest(mockData, page * 10 - 10), 10) // Divides the 100 data by chunks of 10
resolve(Object.assign({}, products))
}, 100)
})
}
}
export default ProductApi
The getProducts
method will be triggered by the redux action to fetch the data. Refer src/actions/productActions.js on how to trigger from action. We also need the data populated on the table once the page is landed. Refer src/index.js on how we dispatch an action. Using the redux reducer, we stored the data into the state called products. Let’s create our component.
For this tutorial, I’m going to create 2 components:
Let’s build our presentational component first.
Create ProductList.js in src/components/home/ProductList.js and paste the following code:
import React, { PropTypes } from 'react';
import { BootstrapTable, TableHeaderColumn } from 'react-bootstrap-table';
/**
A product list component which shows the table with list of data
**/
const ProductList = ({
products,
activePage,
onNavigatePage
}) => {
const productList = products.productList;
const options = {
hideSizePerPage: true,
page: activePage,
onPageChange: onNavigatePage
};
return(
<bootstraptable data="{productList}" fetchinfo="{{dataTotalSize:" products.resultscount}}="" options="{options}" remote="" hover="" pagination=""><tableheadercolumn iskey="" datafield="id">Id</tableheadercolumn>
<tableheadercolumn datafield="productName">Product</tableheadercolumn>
<tableheadercolumn datafield="price">Price</tableheadercolumn>
<tableheadercolumn datafield="manufacturedDate">Manufacture Date</tableheadercolumn>
<tableheadercolumn datafield="expiryDate">Expiry Date</tableheadercolumn></bootstraptable>
);
};
ProductList.propTypes = {
products: PropTypes.object.isRequired,
activePage: PropTypes.number.isRequired,
onNavigatePage: PropTypes.func.isRequired
};
export default ProductList;
We start with importing BootstrapTable
and TableHeaderColumn
from react-bootstrap-table
library.
Then we initialize our ProductList
presentational component with three properties:
In the return, we initiate the BootstrapTable
component with the required parameters which will be passed to our container component to render. Few things to note here:
Next thing, for each field we create a TableHeaderColumn
by saying my id
column is the unique using isKey
attribute.
Let’s create our container component.
Create HomePage.js
in src/components/home/HomePage.js and paste the following there:
import React, { PropTypes } from 'react'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import * as productActions from '../../actions/productActions'
import ProductList from './ProductList'
class HomePage extends React.Component {
constructor(props, context) {
super(props, context)
this.state = {
activePage: 1
}
this.onNavigatePage = this.onNavigatePage.bind(this)
}
// This calls the loadAllProducts action and
// also updates the activePage state to the navigated page number
onNavigatePage(page, sizePerPage) {
this.props.actions.loadAllProducts(page)
this.setState({ activePage: page })
}
render() {
const { products } = this.props
return (
Object.keys(products).length > 0 && (
<ProductList
products={products}
activePage={this.state.activePage}
onNavigatePage={this.onNavigatePage}
/>
)
)
}
}
HomePage.propTypes = {
products: PropTypes.object.isRequired,
actions: PropTypes.object.isRequired
}
function mapStateToProps(state, ownProps) {
return {
products: state.products
}
}
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators(productActions, dispatch)
}
}
export default connect(mapStateToProps, mapDispatchToProps)(HomePage)
Direct jump to render
method. The render
method simply initiates a ProductList
component with the required properties which we have explained earlier.
The onNavigatePage
method is implemented here which takes care of calling the action for the required page and udpates the activePage
state so that the pagination control set the current page as active. That’s it.
Now if you run npm start -s
, and head to browser where it opened http://localhost:3005 you could see the table with pagination as like this:
We’ll again meet soon with the Part-2.