Enterprise Java

Handling Events in React

In post Rendering RESTful service with React we created simple UI which render employee list fetched from RESTful service. As part of this post we will extend the same app to support add and delete employees operation.

We will start with updating react-app backend api with add/delete employee operation along with modifying the existing get employee method to return the list of employees following below steps:

Step 1. Define addEmployee method flagged by @PostMapping(“/employee/add”) which will add employee in a class level employee list:

@PostMapping("/employee/add")
public List<Employee> addEmployee(final @RequestBody Employee employee) {
	System.out.println("Adding employee with name : " + employee.getName());
	if(employee.getName() != null && employee.getName().length() > 0)
              employeeList.add(new Employee(employeeList.size(), employee.getName(), "IT"));
	return employeeList;
}

Step 2. Define deleteEmployee method flagged by @PostMapping(“/employee/delete”) which will delete employee from a class level employee list matching the name of an employee, as follows:

@PostMapping("/employee/delete")
public List<Employee> deleteEmployee(final @RequestBody Employee employee) {
	System.out.println("Deleting employee with name : " + employee.getName());
	final Optional<Employee> optional = employeeList.stream().filter(e -> e.getName().equalsIgnoreCase(employee.getName())).findAny();
	 if(optional.isPresent()){
		employeeList.remove(optional.get());
	 }
	return employeeList;
}

Eventually, ReactAppApplication.java should look like:

@SpringBootApplication
@RestController
public class ReactAppApplication {

	final List<Employee> employeeList = new ArrayList<>();
	
	public static void main(String[] args) {
		SpringApplication.run(ReactAppApplication.class, args);
	}

	@GetMapping("/employee/get")
	public List<Employee> get() {
		return employeeList;
	}
	
	@PostMapping("/employee/add")
	public List<Employee> add(final @RequestBody Employee employee) {
		System.out.println("Adding employee with name : " + employee.getName());
		if(employee.getName() != null && employee.getName().length() > 0)
		 employeeList.add(new Employee(employeeList.size(), employee.getName(), "IT"));
		return employeeList;
	}
	
	@PostMapping("/employee/delete")
	public List<Employee> delete(final @RequestBody Employee employee) {
		System.out.println("Deleting employee with name : " + employee.getName());
		final Optional<Employee> optional = employeeList.stream().filter(e -> e.getName().equalsIgnoreCase(employee.getName())).findAny();
		if(optional.isPresent()){
			employeeList.remove(optional.get());
		}
		return employeeList;
	}
}

Step 3: Define addEmployee method/handler in ReactApp component which make a POST call with an employee name as a payload to the addEmployee method we just defined in our controller, as follows:

/Users/ArpitAggarwal/react-app/app/components/react-app.jsx

addEmployee(employeeName){

		let _this = this;
		this.Axios.post('/add', {
        	name: employeeName
         })
		  .then(function (response) {
		    console.log(response);
		    _this.setState({employees: response.data});
		  })
		  .catch(function (error) {
		    console.log(error);
		  });
}

Step 4: Bind addEmployee handler in the constructor of ReactApp component:

constructor(props) {
		super(props);
		this.state = {employees: []};
		this.addEmployee = this.addEmployee.bind(this);
		this.Axios = axios.create({
		    baseURL: "/employee",
		    headers: {'content-type': 'application/json', 'creds':'user'}
		});
}

Step 5: Render the child component – AddEmployee as part of ReactApp component render method, passing addEmployee handler as react props to establish the parent child communication:

render() {
		return (
				<div>
				  <AddEmployee addEmployee={this.addEmployee}/>
				  <EmployeeList employees={this.state.employees}/>
		        </div>
		)
}

Step 6: Create add-employee component inside component directory, as follows:

cd react-app/app/components/
touch add-employee.jsx

And copy the following content:

react-app/app/components/add-employee.jsx

import React, { Component, PropTypes } from 'react'

export default class AddEmployee extends React.Component {

  render(){
    return (
       <div>
          <input type = 'text' ref = 'input' />
          <button onClick = {(e) => this.handleClick(e)}>
             Add Employee
          </button>
       </div>
    )
  }
  handleClick(e) {
     const node = this.refs.input
     const text = node.value.trim()
     console.log(text);
     this.props.addEmployee(text)
     node.value = ''
  }
}

handleClick(e) function defined above is called on Add Employee button click which will further call addEmployee handler defined in ReactApp using props.

With all this in place, our react-app can perform add employee operation. Next we will extend the same to support delete employee operation, following further steps.

Step 7: Define deleteEmployee handler and bind it in ReactApp in the same way we did for addEmployee handler:

/Users/ArpitAggarwal/react-app/app/components/react-app.jsx

constructor(props) {
		super(props);
		this.state = {employees: []};
		this.addEmployee = this.addEmployee.bind(this);
		this.deleteEmployee = this.deleteEmployee.bind(this);
		this.Axios = axios.create({
		    baseURL: "/employee",
		    headers: {'content-type': 'application/json', 'creds':'user'}
		});
}

deleteEmployee(employeeName){
        let _this = this;
        this.Axios.post('/delete', {
        	name: employeeName
          })
          .then(function (response) {
        	_this.setState({employees: response.data});
            console.log(response);
          })
          .catch(function (error) {
            console.log(error);
          });
}

Step 8: Pass deleteEmployee handler to the EmployeeList component which will further pass it to it’s child container:

render() {
		return (
				<div>
				  <AddEmployee addEmployee={this.addEmployee}/>
				  <EmployeeList employees={this.state.employees} deleteEmployee={this.deleteEmployee}/>
		        </div>
			)
	}

Eventually, ReactApp component should look like:

'use strict';
const React = require('react');
var axios = require('axios');

import EmployeeList from './employee-list.jsx'
import AddEmployee from './add-employee.jsx'

export default class ReactApp extends React.Component {

	constructor(props) {
		super(props);
		this.state = {employees: []};
		this.addEmployee = this.addEmployee.bind(this);
		this.deleteEmployee = this.deleteEmployee.bind(this);
		this.Axios = axios.create({
		    baseURL: "/employee",
		    headers: {'content-type': 'application/json', 'creds':'user'}
		});
	}

	componentDidMount() {
		let _this = this;
		this.Axios.get('/get')
		  .then(function (response) {
		     console.log(response);
		    _this.setState({employees: response.data});
		  })
		  .catch(function (error) {
		    console.log(error);
		  });
	}
	
	addEmployee(employeeName){

		let _this = this;
		this.Axios.post('/add', {
        	name: employeeName
         })
		  .then(function (response) {
		    console.log(response);
		    _this.setState({employees: response.data});
		  })
		  .catch(function (error) {
		    console.log(error);
		  });
    }
    
    deleteEmployee(employeeName){
        let _this = this;
        this.Axios.post('/delete', {
        	name: employeeName
          })
          .then(function (response) {
        	_this.setState({employees: response.data});
            console.log(response);
          })
          .catch(function (error) {
            console.log(error);
          });
    }
	render() {
		return (
				<div>
				  <AddEmployee addEmployee={this.addEmployee}/>
				  <EmployeeList employees={this.state.employees} deleteEmployee={this.deleteEmployee}/>
		        </div>
			)
	}
}

Step 9: Update EmployeeList component to pass the deleteEmployee handler to it’s child component – Employee by importing it along with the change in render method to have a Delete 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>
					</tr>
					{employees}
				</tbody>
			</table>
		)
	}
}

Step 10: Update Employee component to render – DeleteEmployee component passing the deleteEmployee handler:

const React = require('react');
import DeleteEmployee from './delete-employee.jsx'

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>
			</tr>
		)
	}
}

Step 11: Create delete-employee component inside component directory:

cd react-app/app/components/
touch delete-employee.jsx

And copy the following content:

react-app/app/components/delete-employee.jsx

import React, { Component, PropTypes } from 'react'

export default class DeleteEmployee extends React.Component {
  render(){
    return (
          <button onClick = {(employeeName) => this.handleDelete(employeeName)}>
             Delete
          </button>
    )

}
  handleDelete(employeeName) {
   this.props.deleteEmployee(employeeName);
  }
}

handleDelete(employeeName) function defined above is called on Delete button click which will further call deleteEmployee handler defined in ReactApp using props.

With all in place directory structure should look like:

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

Complete source code is hosted on github.

Reference: Handling Events 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
Inline Feedbacks
View all comments
Back to top button