CRUD Operation Using React Redux - Part Three

Introduction

 
In my last article, we learned the basic concept of Redux Architecture and how to configure Redux Architecture into React application. We are also going through a few newer concepts of Action, Dispatch, Reducer, State, Provider, Connect, which we are going to use when working with Redux.
 
In this article, you will learn to perform CRUD operations in a simpler way.
 
 
A brief overview of the concept Action, Reducer & Dispatch which we are going to use in Redux:
 
Action
 
As a refresher, an action is a simple object that must include a type of value.  As a quick review, our actions can be any object value that has the type key. We can send data along with our action (conventionally, we'll pass extra data along as the payload of an action).

Reducer

The reducer is a pure function that takes the previous state and an action, and returns the next state. (previousState, action) => nextState. It's called a reducer because it's the type of function you would pass to Array.prototype.reduce (reducer, ?initialValue) .

Dispatch

dispatch() is the method used to dispatch actions and trigger state changes to the store. react-redux is simply trying to give you convenient access to it. Note, however, that dispatch is not available on props if you do pass it in actions to your connect function.
 

Step By Step CRUD operation

 
You have already created the store, if not you can read my previous article. I have shared a step by step configuration to create a store for Redux architecture. Once the store is created we need to create action and reducer for operation purposes.
  1. import React from 'react';  
  2. import ReactDOM from 'react-dom';  
  3. import App from './App';  
  4. import { Provider } from 'react-redux';  
  5. import { createStore, applyMiddleware } from 'redux';  
  6. import thunk from "redux-thunk";  
  7. import * as serviceWorker from './serviceWorker';  
  8. import reducer from './Redux/reducer';  
  9.   
  10. const store = createStore(reducer, applyMiddleware(thunk));  
  11.   
  12. ReactDOM.render(  
  13.     <Provider store={store}>  
  14.         <App />  
  15.     </Provider>, document.getElementById('root'));  
  16.   
  17. // If you want your app to work offline and load faster, you can change    
  18. // unregister() to register() below. Note this comes with some pitfalls.    
  19. // Learn more about service workers: http://bit.ly/CRA-PWA    
  20. serviceWorker.unregister();   
Let's  Consider CRUD operations of Employee Module,
  1. LIST OF EMPLOYEE
  2. ADD EMPLOYEE
  3. EDIT EMPLOYEE
  4. DELETE EMPLOYEE
For a better folder structure you need to create action.js and reducer.js files into the Redux folder so that you can easily access from root path.

LIST OF EMPLOYEES

 
Consider the following JSON object of the initial value of employee list
  1. const initialstate = {  
  2.     employees: [  
  3.         { id: 1, employeeName: "Employee 1", employeeDepartment: ".NET Team" },  
  4.         { id: 2, employeeName: "Employee 2", employeeDepartment: "Mobile Team" },  
  5.         { id: 3, employeeName: "Employee 3", employeeDepartment: "Design Team" }  
  6.     ]  
  7. }; 
Create a reducer with the property of GET method.
  1. const reducer = (state = initialstate, action) => {  
  2.     switch (action.type) {  
  3.         case 'GET_EMPLOYEE':  
  4.             return {  
  5.                 ...state  
  6.             };  
  7.         default:  
  8.             return state;  
  9.     }  
  10. };  
  11.   
  12. export default reducer; 
Create an action creator with the property of getting a method.
  1. export function getEmployee() {  
  2.     return dispatch => {  
  3.         return dispatch({  
  4.             type: 'GET_EMPLOYEE'  
  5.         });  
  6.     }  
  7. }; 
On App.js call the method on ComponentDiD mount so that you will get employee listing which was initially assigned in the reducer. 
  1. import React, { Component } from "react";  
  2. import logo from "./logo.svg";  
  3. import "./App.css";  
  4. import PropTypes from 'prop-types';  
  5. import { getEmployee } from './Redux/action';  
  6. import { connect } from 'react-redux';  
  7.   
  8. const mapStateToProps = state => ({  
  9.   employees: state.employees  
  10. });  
  11.   
  12. class App extends Component {  
  13.   constructor(props) {  
  14.     super(props);  
  15.   }  
  16.   
  17.   static propTypes = {  
  18.     employees: PropTypes.array.isRequired,  
  19.     getEmployee: PropTypes.func.isRequired  
  20.   };  
  21.   
  22.   componentDidMount() {  
  23.     this.props.getEmployee();  
  24.   }  
  25.   
  26.   render() {  
  27.     return (  
  28.       <div className="App">  
  29.         <header className="App-header">  
  30.           <img src={logo} className="App-logo" alt="logo" />  
  31.           <h1 className="App-title">CRUD opeartions for Employee Module</h1>  
  32.         </header>  
  33.         <p className="App-intro">  
  34.           <div className="rightsection">  
  35.             <table>  
  36.               <thead>  
  37.                 <tr>  
  38.                   <th>ID</th>  
  39.                   <th>Name</th>  
  40.                   <th>Depatment Name</th>  
  41.                   <th>Action(s)</th>  
  42.                 </tr>  
  43.               </thead>  
  44.               <tbody>  
  45.                 {this.props.employees && this.props.employees.map((data, index) => {  
  46.                   return <tr key={(index + 1)}>  
  47.                     <td>{(index + 1)}</td>  
  48.                     <td>{data.employeeName}</td>  
  49.                     <td>{data.employeeDepartment}</td>  
  50.                     <td><button onClick={() => this.editDetails(data)}>EDIT</button> <button onClick={() => this.deleteEmployee(data.id)}>DELETE</button> </td>  
  51.                   </tr>  
  52.                 })}  
  53.               </tbody>  
  54.             </table>  
  55.           </div>  
  56.         </p>  
  57.       </div>  
  58.     );  
  59.   }  
  60. }  
  61.   
  62. export default connect(mapStateToProps, { getEmployee })(App); 
Run the application:
 
Now, you know how the flow has been followed to work with Redux architecture. I have demonstrated the operation of listing just above. In the same way, you can perform other operations (CREATE-EDIT-DELETE). So let me share with you how Reducer and Action files will be there with all methods.

We need to add all action-creator in Action.Js and actual operations which need to manipulate data in Reducer.js.
 
Reducer.js
  1. const initialstate = {    
  2.     employees: [    
  3.         { id: 1, employeeName: "Employee 1", employeeDepartment: ".NET Team" },    
  4.         { id: 2, employeeName: "Employee 2", employeeDepartment: "Mobile Team" },    
  5.         { id: 3, employeeName: "Employee 3", employeeDepartment: "Design Team" }    
  6.     ]    
  7. };    
  8.     
  9. const reducer = (state = initialstate, action) => {    
  10.     switch (action.type) {    
  11.         case 'GET_EMPLOYEE':    
  12.             return {    
  13.                 ...state    
  14.             };    
  15.         case 'ADD_EMPLOYEE':    
  16.             return {    
  17.                 ...state,    
  18.                 employees: state.employees.concat(action.payload)    
  19.             };    
  20.         case 'EDIT_EMPLOYEE':    
  21.             return {    
  22.                 ...state,    
  23.                 employees: state.employees.map(    
  24.                     (content, i) => content.id === action.payload.id ? {...content, employeeName : action.payload.employeeName ,  employeeDepartment : action.payload.employeeDepartment }    
  25.                                             : content)    
  26.             };    
  27.         case 'DELETE_EMPLOYEE':    
  28.             return {    
  29.                 ...state,    
  30.                 employees: state.employees.filter(item => item.id !== action.payload)    
  31.             };    
  32.         default:    
  33.             return state;    
  34.     }    
  35. };    
  36.     
  37. export default reducer;   
Action.js
  1. export function getEmployee() {  
  2.     return dispatch => {  
  3.         return dispatch({  
  4.             type: 'GET_EMPLOYEE'  
  5.         });  
  6.     }  
  7. };  
  8.   
  9. export function addEmployee(data) {  
  10.     return dispatch => {  
  11.         return dispatch({  
  12.             type: 'ADD_EMPLOYEE',  
  13.             payload: data  
  14.         });  
  15.     }  
  16. };  
  17.   
  18. export function editEmployee(data) {  
  19.     return dispatch => {  
  20.         return dispatch({  
  21.             type: 'EDIT_EMPLOYEE',  
  22.             payload: data  
  23.         });  
  24.     }  
  25. };  
  26.   
  27. export function deleteEmployee(employeeId) {  
  28.     return dispatch => {  
  29.         return dispatch({  
  30.             type: 'DELETE_EMPLOYEE',  
  31.             payload: employeeId  
  32.         });  
  33.     }  
  34. }; 
App.js
  1. import React, { Component } from "react";  
  2. import logo from "./logo.svg";  
  3. import "./App.css";  
  4. import PropTypes from 'prop-types';  
  5. import { getEmployee, addEmployee, editEmployee, deleteEmployee } from './Redux/action';  
  6. import { connect } from 'react-redux';  
  7.   
  8. class App extends Component {  
  9.   constructor(props) {  
  10.     super(props);  
  11.     this.state = {  
  12.       id: 0,  
  13.       employeeName: "",  
  14.       employeeDepartment: ""  
  15.     };  
  16.   }  
  17.   
  18.   static propTypes = {  
  19.     employees: PropTypes.array.isRequired,  
  20.     getEmployee: PropTypes.func.isRequired,  
  21.     addEmployee: PropTypes.func.isRequired,  
  22.     editEmployee: PropTypes.func.isRequired,  
  23.     deleteEmployee: PropTypes.func.isRequired  
  24.   };  
  25.   
  26.   componentDidMount() {  
  27.     this.props.getEmployee();  
  28.   }  
  29.   
  30.   submitData = () => {  
  31.     if (this.state.employeeName && this.state.employeeDepartment && !this.state.id) {  
  32.       const newEmployee = {  
  33.         id: Math.floor(Math.random() * (999 - 100 + 1) + 100),  
  34.         employeeName: this.state.employeeName,  
  35.         employeeDepartment: this.state.employeeDepartment,  
  36.       };  
  37.   
  38.       this.props.addEmployee(newEmployee);  
  39.     } else if (this.state.employeeName && this.state.employeeDepartment && this.state.id) {  
  40.       const updatedDetails = {  
  41.         id: this.state.id,  
  42.         employeeName: this.state.employeeName,  
  43.         employeeDepartment: this.state.employeeDepartment,  
  44.       };  
  45.   
  46.       this.props.editEmployee(updatedDetails);  
  47.     } else {  
  48.       alert('Enter Employee Details.');  
  49.     }  
  50.   
  51.     this.clearData();  
  52.   }  
  53.   
  54.   editDetails = (data) => {  
  55.     this.setState({  
  56.       id: data.id,  
  57.       employeeName: data.employeeName,  
  58.       employeeDepartment: data.employeeDepartment  
  59.     })  
  60.   }  
  61.   
  62.   deleteEmployee = (id) => {  
  63.     this.clearData();  
  64.     if (window.confirm("Are you sure?")) {  
  65.       this.props.deleteEmployee(id);  
  66.     }  
  67.   }  
  68.   
  69.   handleNameChange = (e) => {  
  70.     this.setState({  
  71.       employeeName: e.target.value  
  72.     });  
  73.   }  
  74.   
  75.   handleDepartmentChange = (e) => {  
  76.     this.setState({  
  77.       employeeDepartment: e.target.value  
  78.     });  
  79.   }  
  80.   
  81.   clearData = () => {  
  82.     this.setState({  
  83.       id: 0,  
  84.       employeeName: "",  
  85.       employeeDepartment: ""  
  86.     });  
  87.   }  
  88.   
  89.   render() {  
  90.     return (  
  91.       <div className="App">  
  92.         <header className="App-header">  
  93.           <img src={logo} className="App-logo" alt="logo" />  
  94.           <h1 className="App-title">CRUD opeartions for Employee Module</h1>  
  95.         </header>  
  96.         <p className="App-intro">  
  97.           <div className="leftsection">  
  98.             Employee Name : <input onChange={this.handleNameChange} value={this.state.employeeName} type="text" placeholder="Employee Name" /> <br />  
  99.             Employee Department :  <input onChange={this.handleDepartmentChange} value={this.state.employeeDepartment} type="text" placeholder="Employee Department" /><br />  
  100.             {this.state.id ? <button onClick={this.submitData}>UPDATE</button> : <button onClick={this.submitData}>ADD</button>}   <button onClick={this.clearData}>CLEAR</button>  
  101.           </div>  
  102.           <div className="rightsection">  
  103.             <table>  
  104.               <thead>  
  105.                 <tr>  
  106.                   <th>ID</th>  
  107.                   <th>Name</th>  
  108.                   <th>Depatment Name</th>  
  109.                   <th>Action(s)</th>  
  110.                 </tr>  
  111.               </thead>  
  112.               <tbody>  
  113.                 {this.props.employees && this.props.employees.map((data, index) => {  
  114.                   return <tr key={(index + 1)}>  
  115.                     <td>{(index + 1)}</td>  
  116.                     <td>{data.employeeName}</td>  
  117.                     <td>{data.employeeDepartment}</td>  
  118.                     <td><button onClick={() => this.editDetails(data)}>EDIT</button> <button onClick={() => this.deleteEmployee(data.id)}>DELETE</button> </td>  
  119.                   </tr>  
  120.                 })}  
  121.               </tbody>  
  122.             </table>  
  123.           </div>  
  124.         </p>  
  125.       </div>  
  126.     );  
  127.   }  
  128. }  
  129.   
  130. const mapStateToProps = state => ({  
  131.   employees: state.employees  
  132. });  
  133.   
  134. export default connect(mapStateToProps, { getEmployee, addEmployee, editEmployee, deleteEmployee })(App); 

Summary

 
With this article, you can set up and configure the Redux architecture in your React application. The Redux structure is complicated but once you build or gain the basic concept of Redux you will have structured Redux in your application. The core concept of the Redux is action, reducer, action-creator, store, connection, etc.

I have made a simple example of CRUD operations using React-Redux. You should try this sample at least 2-3 times so that it helps you to clear out about the Redux concept.

I hope this helps you.