Software Development

Routing in React

In post Handling Events in React we extended react-app which we built as part of Rendering RESTful service with React to support add and delete employees operation.

Now as part of this post we will add Routing capabilities to it using react-router, by defining an additional column Details as a Link, click of which take you to the details of the employee selected, following below steps:

Step 1. Install react-router-dom as a dependency:

npm install react-router-dom --save

Step 2: Update react-handling-events/app/main.js to import HashRouter, Route and Switch from react-router-dom along with EmployeeDetail component which we will define later in the post.

import { HashRouter, Route, Switch } from 'react-router-dom';
import EmployeeDetail from './components/employee-detail.jsx'

Step 3: Instead of rendering the ReactApp component directly, we will use HashRouter and Route to render it:

ReactDOM.render(
	<HashRouter>
	 <Switch>
	    <Route exact path="/" component={ReactApp}/>
        <Route exact path="/employee/:id" component={EmployeeDetail}/>
     </Switch>
    </HashRouter>,
   document.getElementById('react')
)

Eventually, react-handling-events/app/main.js should look like:

'use strict';
const React = require('react');
const ReactDOM = require('react-dom')

import { HashRouter, Route, Switch } from 'react-router-dom';
import ReactApp from './components/react-app.jsx'
import EmployeeDetail from './components/employee-detail.jsx'

ReactDOM.render(
    <HashRouter>
      <Switch>
        <Route exact path="/" component={ReactApp}/>
        <Route exact path="/employee/:id" component={EmployeeDetail}/>
      </Switch>
    </HashRouter>,
  document.getElementById('react')
)

HashRouter tag specified above puts route information into the hash of the URL (after the #). I preferred HashRouter over BrowserRouter because to use BrowserRouter web server must be ready to handle real URLs. When the app first loads at / it will probably work, but as the user navigates around and then hits refresh at /employee/1 web server will get a request to /employee/1 then I have to handle that URL and include JavaScript application in the response.

Switch tag specified above renders the first child Route that matches the location.

As we defined two Route tag above, let’s understand what each one of them signify.

<Route exact path=“/“ component={ReactApp}/> renders ReactApp component when the app loads at / .

<Route exact path=“/employee/:id“ component={EmployeeDetail}/> renders EmployeeDetail component when the app loads at /employee/{id} where id is a dynamic path variable.

Step 4: Create employee-detail.jsx component inside component directory, as follows:

cd react-handling-events/app/components/
touch employee-detail.jsx

And copy the below content:

import React, { Component } from 'react'

export default class EmployeeDetail extends Component {
  render(){
    if(this.props.match !== undefined && this.props.match.params !== undefined ){
      return(
        <div>
          <table style={{border: '1px solid black'}}>
            <tbody><tr>
              <td>Id</td>
              <td>Name</td>
              <td>Department</td>
            </tr>
            <tr>
              <td>{this.props.match.params.id}</td>
              <td>{this.props.location.query.employee.name}</td>
              <td>{this.props.location.query.employee.department}</td>
            </tr>
          </tbody>
        </table>
      </div>
    );
  }
  return (null);
}
}

{this.props.match.params.id} specified above is to access route params in the component.

{this.props.location.query.employee.name} specified above is to access query params in the component which React-router injects as a location property.

Step 5: Update EmployeeList component render method to have an additional Details column:

const React = require('react');
import Employee from './employee.jsx'

export default class EmployeeList extends React.Component{
    
    render() {
		var employees = this.props.employees.map((employee, i) =>
			<Employee key={i} employee={employee} deleteEmployee={() => this.props.deleteEmployee(employee.name)}/>
		);
		
		return (
			<table>
				<tbody>
					<tr>
						<th>ID</th>
						<th>Name</th>
						<th>Department</th>
						<th>Delete</th>
						<th>Details</th>
					</tr>
					{employees}
				</tbody>
			</table>
		)
	}
}

Step 6: Update Employee component to import Link from react-router-dom along with render method to have an additional column Details as a Link, click on which take you to the details of the employee:

const React = require('react');
import DeleteEmployee from './delete-employee.jsx'
import { Link } from 'react-router-dom';

export default class Employee extends React.Component{
	render() {
		return (
			<tr>
				<td>{this.props.employee.id}</td>
				<td>{this.props.employee.name}</td>
				<td>{this.props.employee.department}</td>
				<td><DeleteEmployee deleteEmployee={this.props.deleteEmployee}/></td>
				<td><Link to={{ pathname:'/employee/'+this.props.employee.id, query: {employee: this.props.employee } }}>Details</Link></td>
			</tr>
		)
	}
}

With all in place directory structure should look like:

Now re-run the application and visit http://localhost:8080it should look like as shown in below screenshot, once you add few employee.


Complete source code is hosted on github.

Reference: Routing in React from our JCG partner Arpit Aggarwal at the Arpit Aggarwal blog.

Arpit Aggarwal

Arpit is a Consultant at Xebia India. He has been designing and building J2EE applications since more than 6 years. He is fond of Object Oriented and lover of Functional programming. You can read more of his writings at aggarwalarpit.wordpress.com
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back to top button