In this article, we’ll walk through building a fully functional CRUD (Create, Read, Update, Delete) application using React, Redux Toolkit, and RTK Query. We’ll also use JSON Server to mock an API.
Prerequisites
- Basic knowledge of React
- Familiarity with Redux Toolkit
- Node.js and npm installed on your machine
Step 1: Setting Up the React Project
First, create a new React application and install the necessary dependencies:
npx create-react-app react-crud-app
cd react-crud-app
npm install axios react-router-dom@6 @reduxjs/toolkit react-redux
Let’s walk through the steps to set up a new React application with the specified packages using the following commands:
npx create-react-app react-crud-app
1. Create a New React Application
First, create a new React application using create-react-app
:
npx create-react-app react-crud-app
: This command usesnpx
to run thecreate-react-app
tool, which sets up a new React project namedreact-crud-app
with all the necessary configurations and dependencies.
cd react-crud-app
2. Navigate into the Project Directory
Change your working directory to the newly created project directory:
cd react-crud-app
: This command changes the current working directory to thereact-crud-app
directory, which was created in the previous step.
npm install axios react-router-dom@6 @reduxjs/toolkit react-redux
3. Install Additional Packages
Install the required additional packages:
axios
: A promise-based HTTP client for making requests to external APIs.react-router-dom@6
: The React Router library for handling navigation within a React application. The@6
specifies version 6, which is the latest major version.@reduxjs/toolkit
: A set of tools that helps to write Redux logic in a standardized way, simplifying common tasks and reducing boilerplate.react-redux
: Official React bindings for Redux, providing React components with easy access to the Redux store.
Step 2: Setting Up JSON Server
We’ll use JSON Server to create a mock API for our application. Create a db.json
file in the root of your project with the following content:
{
"employees": [
{ "id": 1, "firstName": "Ramesh", "lastName": "Fadatare", "email": "ram@gmail.com" },
{ "id": 2, "firstName": "John", "lastName": "Cena", "email": "john@gmail.com" },
{ "id": 3, "firstName": "Tom", "lastName": "Cruise", "email": "tom@gmail.com" },
{ "id": 4, "firstName": "Admin", "lastName": "admin", "email": "admin@gmail.com" }
]
}
Install JSON Server globally and start it:
npm install -g json-server
json-server --watch db.json --port 5000
Let’s walk through the steps to set up a mock backend using json-server
and integrate it with your React application.
npm install -g json-server
1. Install json-server
Globally
Install json-server
globally on your system:
npm install -g json-server
: This command installsjson-server
globally, allowing you to use it from any directory on your system.
{
"employees": [
{ "id": 1, "firstName": "Ramesh", "lastName": "Fadatare", "email": "ram@gmail.com" },
{ "id": 2, "firstName": "John", "lastName": "Cena", "email": "john@gmail.com" },
{ "id": 3, "firstName": "Tom", "lastName": "Cruise", "email": "tom@gmail.com" },
{ "id": 4, "firstName": "Admin", "lastName": "admin", "email": "admin@gmail.com" }
]
}
2. Create a db.json
File
Create a db.json
file in the root directory of your React project (react-crud-app
). This file will contain your mock data. Here is an example structure for employee data:
json-server --watch db.json --port 5000
3. Start json-server
Start json-server
and watch the db.json
file for changes, running it on port 5000:
json-server --watch db.json --port 5000
: This command startsjson-server
and serves the content ofdb.json
as a RESTful API on port 5000. The--watch
flag makes sure thatjson-server
watches for changes indb.json
and updates the API accordingly.
Your JSON Server will now be running at http://localhost:5000
.
Step 3: Creating Redux Store and API Slice
Next, set up the Redux store and API slice using RTK Query. This will handle data fetching and caching for our application.
Creating the Redux Store
Create a store.js
file in the src/app
directory:
import { configureStore } from '@reduxjs/toolkit';
import { employeeApi } from '../features/employees/employeeApi';
export const store = configureStore({
reducer: {
[employeeApi.reducerPath]: employeeApi.reducer,
},
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().concat(employeeApi.middleware),
});
export default store;
Let’s break down the configureStore
setup and integrate it with your React application step-by-step.
import { configureStore } from '@reduxjs/toolkit';
import { employeeApi } from '../features/employees/employeeApi';
1. Import Statements
configureStore
: This function is from Redux Toolkit. It simplifies the process of creating a Redux store by providing good defaults and automatically setting up the Redux DevTools extension.employeeApi
: This is an API slice created using Redux Toolkit’screateApi
function. It manages the logic for making API requests and handling the state related to those requests.
export const store = configureStore({
reducer: {
[employeeApi.reducerPath]: employeeApi.reducer,
},
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().concat(employeeApi.middleware),
});
2. Configuring the Store
reducer
: This field specifies the reducers for the Redux store. It is an object where each key is a slice of the state and the value is the reducer function for that slice.[employeeApi.reducerPath]
: ThereducerPath
is a unique key that identifies the slice of state managed byemployeeApi
. This is typically a string like'employeeApi'
.employeeApi.reducer
: This is the reducer function provided by theemployeeApi
slice. It handles actions and updates the state related to API requests made byemployeeApi
.
middleware
: This field allows you to customize the middleware for the store. Middleware in Redux are functions that run between an action being dispatched and the action reaching the reducer.getDefaultMiddleware()
: This function returns the default middleware configuration provided by Redux Toolkit, which includes middleware for handling asynchronous actions and other common tasks..concat(employeeApi.middleware)
: This adds the middleware fromemployeeApi
to the default middleware. TheemployeeApi.middleware
handles the side effects of API requests, such as making HTTP requests and caching responses.
export default store;
3. Exporting the Store
- This line exports the configured Redux store so that it can be used throughout your application. By exporting the store, you can import it in your main application file and provide it to your React application using the
Provider
component fromreact-redux
.
Summary
Imports:
configureStore
from Redux Toolkit to set up the Redux store.employeeApi
from youremployeeApi
slice to manage API requests.
Configure the store:
- Add the
employeeApi
reducer to the store’s reducers. - Include
employeeApi.middleware
in the store’s middleware to handle side effects of API requests.
- Add the
Export the store:
- Export the configured store for use in your React application.
This setup allows your React application to manage state using Redux, handle API requests with the employeeApi
slice, and includes middleware to manage side effects and async operations efficiently.
Creating the API Slice
Create an employeeApi.js
file in the src/features/employees
directory:
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
export const employeeApi = createApi({
reducerPath: 'employeeApi',
baseQuery: fetchBaseQuery({ baseUrl: 'http://localhost:5000/' }),
endpoints: (builder) => ({
getEmployees: builder.query({
query: () => 'employees',
}),
getEmployee: builder.query({
query: (id) => `employees/${id}`,
}),
addEmployee: builder.mutation({
query: (employee) => ({
url: 'employees',
method: 'POST',
body: employee,
}),
}),
updateEmployee: builder.mutation({
query: ({ id, employee }) => ({
url: `employees/${id}`,
method: 'PUT',
body: employee,
}),
}),
deleteEmployee: builder.mutation({
query: (id) => ({
url: `employees/${id}`,
method: 'DELETE',
}),
}),
}),
});
export const {
useGetEmployeesQuery,
useGetEmployeeQuery,
useAddEmployeeMutation,
useUpdateEmployeeMutation,
useDeleteEmployeeMutation,
} = employeeApi;
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
Let’s break down the code and explain each part step by step.
Import Statements
createApi
: This function is from Redux Toolkit’s Query module. It is used to define a set of API endpoints and automatically generate the corresponding hooks for making requests.fetchBaseQuery
: A small wrapper around the standardfetch
API that simplifies making requests to the server.
export const employeeApi = createApi({
reducerPath: 'employeeApi',
baseQuery: fetchBaseQuery({ baseUrl: 'http://localhost:5000/' }),
endpoints: (builder) => ({
getEmployees: builder.query({
query: () => 'employees',
}),
getEmployee: builder.query({
query: (id) => `employees/${id}`,
}),
addEmployee: builder.mutation({
query: (employee) => ({
url: 'employees',
method: 'POST',
body: employee,
}),
}),
updateEmployee: builder.mutation({
query: ({ id, employee }) => ({
url: `employees/${id}`,
method: 'PUT',
body: employee,
}),
}),
deleteEmployee: builder.mutation({
query: (id) => ({
url: `employees/${id}`,
method: 'DELETE',
}),
}),
}),
});
Define the employeeApi
reducerPath
:reducerPath: 'employeeApi'
: This specifies the key in the Redux store where the reducer will be mounted. It’s a unique identifier for this API slice.
baseQuery
:baseQuery: fetchBaseQuery({ baseUrl: 'http://localhost:5000/' })
: This configures the base URL for all requests made by this API slice. Here, it’s set tohttp://localhost:5000/
, which means all API requests will be made relative to this URL.
endpoints
:- This is a function that defines the various endpoints (API operations) for this slice. The
builder
object is used to define different types of requests (queries and mutations).
- This is a function that defines the various endpoints (API operations) for this slice. The
getEmployees: builder.query({
query: () => 'employees',
}),
Defining Endpoints
getEmployees
:- Defines a query endpoint to fetch the list of employees. The URL for this request will be
http://localhost:5000/employees
getEmployee: builder.query({
query: (id) => `employees/${id}`,
}),
Define getEmployee
:
- Defines a query endpoint to fetch a single employee by ID. The URL for this request will be
http://localhost:5000/employees/{id}
.
addEmployee: builder.mutation({
query: (employee) => ({
url: 'employees',
method: 'POST',
body: employee,
}),
}),
Define addEmployee
:
- Defines a mutation endpoint to add a new employee. The request will be a POST to
http://localhost:5000/employees
with the new employee data in the body.
updateEmployee: builder.mutation({
query: ({ id, employee }) => ({
url: `employees/${id}`,
method: 'PUT',
body: employee,
}),
}),
Define: updateEmployee
:
- Defines a mutation endpoint to update an existing employee. The request will be a PUT to
http://localhost:5000/employees/{id}
with the updated employee data in the body.
deleteEmployee: builder.mutation({
query: (id) => ({
url: `employees/${id}`,
method: 'DELETE',
}),
}),
Define deleteEmployee
:
- Defines a mutation endpoint to delete an employee by ID. The request will be a DELETE to
http://localhost:5000/employees/{id}
.
export const {
useGetEmployeesQuery,
useGetEmployeeQuery,
useAddEmployeeMutation,
useUpdateEmployeeMutation,
useDeleteEmployeeMutation,
} = employeeApi;
Exporting Hooks
- These hooks are automatically generated by
createApi
based on the defined endpoints. They provide a simple way to make requests and manage state within your React components:useGetEmployeesQuery
: Hook for fetching the list of employees.useGetEmployeeQuery
: Hook for fetching a single employee by ID.useAddEmployeeMutation
: Hook for adding a new employee.useUpdateEmployeeMutation
: Hook for updating an existing employee.useDeleteEmployeeMutation
: Hook for deleting an employee by ID.
Summary
createApi
: Used to define API endpoints and generate corresponding hooks.fetchBaseQuery
: Simplifies making HTTP requests by wrapping the standardfetch
API.- Endpoints: Defined using
builder.query
for read operations (GET) andbuilder.mutation
for write operations (POST, PUT, DELETE). - Generated Hooks: Simplify making API requests and managing state within React components.
This setup allows you to easily interact with a REST API, manage data fetching, and handle state updates within your Redux-powered React application.
Step 4: Creating Components
Now, create the necessary components for our application. Each component will use the RTK Query hooks to manage state.
Employee List Component
Create EmployeeList.js
in the src/components
directory:
import React from 'react';
import { useGetEmployeesQuery } from '../features/employees/employeeApi';
import { Link } from 'react-router-dom';
const EmployeeList = () => {
const { data: employees, error, isLoading } = useGetEmployeesQuery();
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<div className="employee-list">
<h2>Employees List</h2>
<Link to="/add" className="btn btn-primary">Add Employee</Link>
<table className="table">
<thead>
<tr>
<th>Employee First Name</th>
<th>Employee Last Name</th>
<th>Employee Email Id</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{employees.map(employee => (
<tr key={employee.id}>
<td>{employee.firstName}</td>
<td>{employee.lastName}</td>
<td>{employee.email}</td>
<td>
<Link to={`/update/${employee.id}`} className="btn btn-info">Update</Link>
<Link to={`/delete/${employee.id}`} className="btn btn-danger">Delete</Link>
<Link to={`/view/${employee.id}`} className="btn btn-success">View</Link>
</td>
</tr>
))}
</tbody>
</table>
</div>
);
};
export default EmployeeList;
import React from 'react';
import { useGetEmployeesQuery } from '../features/employees/employeeApi';
import { Link } from 'react-router-dom';
Let’s break down the code for the EmployeeList
component step-by-step to understand what each part does.
Import Statements
- React: The core React library for building user interfaces.
useGetEmployeesQuery
: A custom hook generated by Redux Toolkit Query for fetching the list of employees.- Link: A component from
react-router-dom
used for creating navigation links.
const { data: employees, error, isLoading } = useGetEmployeesQuery();
EmployeeList Component
1. Fetching Data
useGetEmployeesQuery
: This hook is used to fetch the list of employees. It returns an object with several properties:data
: The fetched data, which is renamed toemployees
using destructuring.error
: Any error that occurred during the fetch operation.isLoading
: A boolean indicating whether the data is still being loaded.
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
2. Handling Loading and Error States
- Loading State: If
isLoading
istrue
, a loading message is displayed. - Error State: If there is an
error
, an error message is displayed.
return (
<div className="employee-list">
<h2>Employees List</h2>
<Link to="/add" className="btn btn-primary">Add Employee</Link>
<table className="table">
<thead>
<tr>
<th>Employee First Name</th>
<th>Employee Last Name</th>
<th>Employee Email Id</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{employees.map(employee => (
<tr key={employee.id}>
<td>{employee.firstName}</td>
<td>{employee.lastName}</td>
<td>{employee.email}</td>
<td>
<Link to={`/update/${employee.id}`} className="btn btn-info">Update</Link>
<Link to={`/delete/${employee.id}`} className="btn btn-danger">Delete</Link>
<Link to={`/view/${employee.id}`} className="btn btn-success">View</Link>
</td>
</tr>
))}
</tbody>
</table>
</div>
);
3. Rendering the Employee List
- Container: The main content is wrapped in a
div
with the classemployee-list
. - Heading: A heading (
h2
) displays “Employees List”. - Add Employee Link: A link to add a new employee, styled as a primary button, navigates to the
/add
route. - Table: A table displays the list of employees:
- Table Head: Defines the column titles.
- Table Body: Maps over the
employees
array and renders a row (tr
) for each employee.- Row Cells: Each row displays the employee’s first name, last name, and email.
- Action Links: Links for updating, deleting, and viewing details of an employee. Each link navigates to a different route with the employee’s ID.
Summary
- Imports: The necessary React library, custom hook for fetching employees, and
Link
component for navigation. - Data Fetching: Uses
useGetEmployeesQuery
to fetch employee data. - State Handling: Displays loading and error messages based on the fetch status.
- Rendering: Displays a list of employees in a table format with action links for each employee.
This component effectively fetches and displays a list of employees, providing actions to view, update, or delete individual employees and a link to add new employees.
Add Employee Component
Create AddEmployee.js
in the src/components
directory:
import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { useAddEmployeeMutation } from '../features/employees/employeeApi';
const AddEmployee = () => {
const [employee, setEmployee] = useState({ firstName: '', lastName: '', email: '' });
const [addEmployee] = useAddEmployeeMutation();
const navigate = useNavigate();
const handleChange = (e) => {
const { name, value } = e.target;
setEmployee({ ...employee, [name]: value });
};
const handleSubmit = async (e) => {
e.preventDefault();
await addEmployee(employee);
navigate('/');
};
return (
<div className="add-employee">
<h2>Add Employee</h2>
<form onSubmit={handleSubmit}>
<div className="form-group">
<label>First Name</label>
<input type="text" name="firstName" value={employee.firstName} onChange={handleChange} required />
</div>
<div className="form-group">
<label>Last Name</label>
<input type="text" name="lastName" value={employee.lastName} onChange={handleChange} required />
</div>
<div className="form-group">
<label>Email</label>
<input type="email" name="email" value={employee.email} onChange={handleChange} required />
</div>
<button type="submit" className="btn btn-primary">Add</button>
</form>
</div>
);
};
export default AddEmployee;
import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { useAddEmployeeMutation } from '../features/employees/employeeApi';
Let’s break down the code for the AddEmployee
component step-by-step to understand what each part does.
Import Statements
- React: The core React library for building user interfaces.
- useState: A React hook to manage state in functional components.
- useNavigate: A hook from
react-router-dom
to programmatically navigate between routes. - useAddEmployeeMutation: A custom hook generated by Redux Toolkit Query for performing the add employee mutation.
const [employee, setEmployee] = useState({ firstName: '', lastName: '', email: '' });
const [addEmployee] = useAddEmployeeMutation();
const navigate = useNavigate();
Component Definition
State and Hooks
employee
: State to hold the new employee’s information (first name, last name, and email).setEmployee
: Function to update theemployee
state.addEmployee
: Mutation function to add a new employee using the API.navigate
: Function to navigate programmatically to different routes
const handleChange = (e) => {
const { name, value } = e.target;
setEmployee({ ...employee, [name]: value });
};
Handling Input Changes
- handleChange: Updates the
employee
state whenever an input field changes. It uses the input field’sname
attribute to determine which property to update.
const handleSubmit = async (e) => {
e.preventDefault();
await addEmployee(employee);
navigate('/');
};
Handling Form Submission
- handleSubmit: Prevents the default form submission behavior, calls the
addEmployee
mutation with the currentemployee
state, and navigates back to the home page (/
) upon successful submission.
return (
<div className="add-employee">
<h2>Add Employee</h2>
<form onSubmit={handleSubmit}>
<div className="form-group">
<label>First Name</label>
<input type="text" name="firstName" value={employee.firstName} onChange={handleChange} required />
</div>
<div className="form-group">
<label>Last Name</label>
<input type="text" name="lastName" value={employee.lastName} onChange={handleChange} required />
</div>
<div className="form-group">
<label>Email</label>
<input type="email" name="email" value={employee.email} onChange={handleChange} required />
</div>
<button type="submit" className="btn btn-primary">Add</button>
</form>
</div>
);
JSX Template
- Container: The main content is wrapped in a
div
with the classadd-employee
. - Heading: A heading (
h2
) displays “Add Employee”. - Form: A form to capture the new employee’s details.
- Form Groups: Each group contains a label and an input field for first name, last name, and email.
- Input Fields: Controlled components that update the
employee
state on change. - Submit Button: A button to submit the form and add the new employee.
Summary
- Imports: Import the necessary libraries and hooks.
- State Management: Use React’s
useState
to manage the form state. - Mutation Hook: Use
useAddEmployeeMutation
to add a new employee via the API. - Navigation: Use
useNavigate
to navigate back to the home page after adding an employee. - Event Handlers: Handle input changes and form submission.
- Rendering: Render a form to collect new employee details and a submit button to trigger the mutation.
This component provides a user interface to add a new employee by filling out a form and submitting it, which triggers the API call to add the employee and then navigates back to the home page.
Update Employee Component
Create UpdateEmployee.js
in the src/components
directory:
import React, { useState, useEffect } from 'react';
import { useParams, useNavigate } from 'react-router-dom';
import { useGetEmployeeQuery, useUpdateEmployeeMutation } from '../features/employees/employeeApi';
const UpdateEmployee = () => {
const { id } = useParams();
const { data: employeeData } = useGetEmployeeQuery(id);
const [employee, setEmployee] = useState({ firstName: '', lastName: '', email: '' });
const [updateEmployee] = useUpdateEmployeeMutation();
const navigate = useNavigate();
useEffect(() => {
if (employeeData) {
setEmployee(employeeData);
}
}, [employeeData]);
const handleChange = (e) => {
const { name, value } = e.target;
setEmployee({ ...employee, [name]: value });
};
const handleSubmit = async (e) => {
e.preventDefault();
await updateEmployee({ id, employee });
navigate('/');
};
return (
<div className="update-employee">
<h2>Update Employee</h2>
<form onSubmit={handleSubmit}>
<div className="form-group">
<label>First Name</label>
<input type="text" name="firstName" value={employee.firstName} onChange={handleChange} required />
</div>
<div className="form-group">
<label>Last Name</label>
<input type="text" name="lastName" value={employee.lastName} onChange={handleChange} required />
</div>
<div className="form-group">
<label>Email</label>
<input type="email" name="email" value={employee.email} onChange={handleChange} required />
</div>
<button type="submit" className="btn btn-primary">Update</button>
</form>
</div>
);
};
export default UpdateEmployee;
Let’s break down the UpdateEmployee
component step-by-step to understand its functionality and how it works.
import React, { useState, useEffect } from 'react';
import { useParams, useNavigate } from 'react-router-dom';
import { useGetEmployeeQuery, useUpdateEmployeeMutation } from '../features/employees/employeeApi';
Import Statements
- React: The core React library.
- useState: A React hook to manage the component’s state.
- useEffect: A React hook to perform side effects in the component.
- useParams: A hook from
react-router-dom
to access URL parameters. - useNavigate: A hook from
react-router-dom
for programmatic navigation. - useGetEmployeeQuery: A custom hook generated by Redux Toolkit Query to fetch a specific employee by ID.
- useUpdateEmployeeMutation: A custom hook generated by Redux Toolkit Query to update an existing employee.
const { id } = useParams();
const { data: employeeData } = useGetEmployeeQuery(id);
const [employee, setEmployee] = useState({ firstName: '', lastName: '', email: '' });
const [updateEmployee] = useUpdateEmployeeMutation();
const navigate = useNavigate();
Component Definition
State and Hooks
useParams
: Extracts theid
parameter from the URL, which is used to fetch the specific employee.useGetEmployeeQuery
: Fetches the employee data for the givenid
. Thedata
property is renamed toemployeeData
.useState
: Initializes theemployee
state with empty fields forfirstName
,lastName
, andemail
.useUpdateEmployeeMutation
: Provides theupdateEmployee
mutation function to update an existing employee.useNavigate
: Provides thenavigate
function for navigation.
useEffect(() => {
if (employeeData) {
setEmployee(employeeData);
}
}, [employeeData]);
Effect to Set Employee Data
- useEffect: Runs when
employeeData
changes. IfemployeeData
is available, it updates theemployee
state with the fetched data.
const handleChange = (e) => {
const { name, value } = e.target;
setEmployee({ ...employee, [name]: value });
};
Handling Input Changes
- handleChange: Updates the
employee
state whenever an input field changes. It uses the input field’sname
attribute to determine which property to update.
const handleSubmit = async (e) => {
e.preventDefault();
await updateEmployee({ id, employee });
navigate('/');
};
Handling Form Submission
- handleSubmit: Prevents the default form submission behavior, calls the
updateEmployee
mutation with the currentemployee
state, and navigates back to the home page (/
) upon successful submission.
return (
<div className="update-employee">
<h2>Update Employee</h2>
<form onSubmit={handleSubmit}>
<div className="form-group">
<label>First Name</label>
<input type="text" name="firstName" value={employee.firstName} onChange={handleChange} required />
</div>
<div className="form-group">
<label>Last Name</label>
<input type="text" name="lastName" value={employee.lastName} onChange={handleChange} required />
</div>
<div className="form-group">
<label>Email</label>
<input type="email" name="email" value={employee.email} onChange={handleChange} required />
</div>
<button type="submit" className="btn btn-primary">Update</button>
</form>
</div>
);
JSX Template
- Container: The main content is wrapped in a
div
with the classupdate-employee
. - Heading: A heading (
h2
) displays “Update Employee”. - Form: A form to update the employee’s details.
- Form Groups: Each group contains a label and an input field for first name, last name, and email.
- Input Fields: Controlled components that update the
employee
state on change. - Submit Button: A button to submit the form and update the employee.
Summary
- Imports: Import the necessary libraries and hooks.
- State Management: Use React’s
useState
to manage the form state. - Data Fetching: Use
useGetEmployeeQuery
to fetch the employee data by ID and set it to the state. - Mutation Hook: Use
useUpdateEmployeeMutation
to update the employee data via the API. - Navigation: Use
useNavigate
to navigate back to the home page after updating the employee. - Event Handlers: Handle input changes and form submission.
- Rendering: Render a form to update employee details and a submit button to trigger the mutation.
This component provides a user interface to update an existing employee’s details by fetching the current data, allowing modifications, and submitting the changes to the backend.
View Employee Component
Create ViewEmployee.js
in the src/components
directory:
import React from 'react';
import { useParams } from 'react-router-dom';
import { useGetEmployeeQuery } from '../features/employees/employeeApi';
const ViewEmployee = () => {
const { id } = useParams();
const { data: employee, error, isLoading } = useGetEmployeeQuery(id);
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<div className="view-employee">
<h2>View Employee</h2>
<p>First Name: {employee.firstName}</p>
<p>Last Name: {employee.lastName}</p>
<p>Email: {employee.email}</p>
</div>
);
};
export default ViewEmployee;
Let’s break down the ViewEmployee
component step-by-step to understand its functionality and how it works.
import React from 'react';
import { useParams } from 'react-router-dom';
import { useGetEmployeeQuery } from '../features/employees/employeeApi';
Import Statements
- React: The core React library for building user interfaces.
- useParams: A hook from
react-router-dom
to access URL parameters. - useGetEmployeeQuery: A custom hook generated by Redux Toolkit Query to fetch a specific employee by ID.
const { id } = useParams();
const { data: employee, error, isLoading } = useGetEmployeeQuery(id);
Component Definition
State and Hooks
useParams
: Extracts theid
parameter from the URL. Thisid
is used to fetch the specific employee.useGetEmployeeQuery
: Fetches the employee data for the givenid
. Thedata
property is renamed toemployee
. It also provideserror
andisLoading
states.
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
Handling Loading and Error States
- Loading State: If
isLoading
istrue
, a loading message is displayed. - Error State: If there is an
error
, an error message is displayed.
return (
<div className="view-employee">
<h2>View Employee</h2>
<p>First Name: {employee.firstName}</p>
<p>Last Name: {employee.lastName}</p>
<p>Email: {employee.email}</p>
</div>
);
JSX Template
- Container: The main content is wrapped in a
div
with the classview-employee
. - Heading: A heading (
h2
) displays “View Employee”. - Employee Details: Paragraphs (
p
) display the employee’s first name, last name, and email
Summary
- Imports: Import the necessary libraries and hooks.
- State Management: Use
useParams
to get theid
from the URL anduseGetEmployeeQuery
to fetch the employee data. - Loading and Error Handling: Display appropriate messages while loading or if an error occurs.
- Rendering: Render the employee’s details once the data is successfully fetched.
Delete Employee Component
Create DeleteEmployee.js
in the src/components
directory:
import React, { useEffect } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import { useDeleteEmployeeMutation } from '../features/employees/employeeApi';
const DeleteEmployee = () => {
const { id } = useParams();
const [deleteEmployee] = useDeleteEmployeeMutation();
const navigate = useNavigate();
useEffect(() => {
const deleteEmp = async () => {
await deleteEmployee(id);
navigate('/');
};
deleteEmp();
}, [id, deleteEmployee, navigate]);
return (
<div className="delete-employee">
<h2>Deleting Employee...</h2>
</div>
);
};
export default DeleteEmployee;
Let’s break down the DeleteEmployee
component step-by-step to understand its functionality and how it works.
import React, { useEffect } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import { useDeleteEmployeeMutation } from '../features/employees/employeeApi';
Import Statements
- React: The core React library for building user interfaces.
- useEffect: A React hook to perform side effects in the component.
- useNavigate: A hook from
react-router-dom
to programmatically navigate between routes. - useParams: A hook from
react-router-dom
to access URL parameters. - useDeleteEmployeeMutation: A custom hook generated by Redux Toolkit Query to perform the delete employee mutation.
const { id } = useParams();
const [deleteEmployee] = useDeleteEmployeeMutation();
const navigate = useNavigate();
Component Definition
State and Hooks
useParams
: Extracts theid
parameter from the URL. Thisid
is used to identify which employee to delete.useDeleteEmployeeMutation
: Provides thedeleteEmployee
mutation function to delete an employee using the API.useNavigate
: Provides thenavigate
function for navigation.
useEffect(() => {
const deleteEmp = async () => {
await deleteEmployee(id);
navigate('/');
};
deleteEmp();
}, [id, deleteEmployee, navigate]);
useEffect Hook
- useEffect: Runs when the component mounts. It ensures that the deletion process starts as soon as the component is rendered.
- deleteEmp Function: An async function that calls the
deleteEmployee
mutation with theid
and then navigates back to the home page (/
). - Dependencies: The effect depends on
id
,deleteEmployee
, andnavigate
, ensuring that the effect runs whenever these dependencies change.
return (
<div className="delete-employee">
<h2>Deleting Employee...</h2>
</div>
);
JSX Template
- Container: The main content is wrapped in a
div
with the classdelete-employee
. - Heading: A heading (
h2
) displays “Deleting Employee…” to inform the user that the deletion process is in progress.
Summary
- Imports: Import the necessary libraries and hooks.
- State and Hooks: Use
useParams
to get theid
from the URL,useDeleteEmployeeMutation
to perform the deletion, anduseNavigate
to navigate after deletion. - useEffect: Perform the deletion side-effect when the component mounts.
- Rendering: Render a message indicating that the deletion process is in progress.
Navbar Component
Create Navbar.js
in the src/components
directory:
Let’s break down the Navbar
component step-by-step to understand its functionality and how it works.
import React from 'react';
import { Link } from 'react-router-dom';
Import Statements
- React: The core React library for building user interfaces.
- Link: A component from
react-router-dom
used to create navigation links within the application. It allows for declarative routing and ensures the application doesn’t refresh the page when navigating.
const Navbar = () => {
return (
<nav className="navbar">
<h1>Employee Management App</h1>
<div className="links">
<Link to="/">Home</Link>
<Link to="/add">Add Employee</Link>
</div>
</nav>
);
};
export default Navbar;
Component Definition
The Navbar
component is a functional component that renders a navigation bar for the application.
<nav className="navbar">
JSX Structure
Container: The entire navbar is wrapped in a
nav
element with a class ofnavbar
.
<h1>Employee Management App</h1>
Title: The title of the application, “Employee Management App”, is displayed inside an h1
tag.
<div className="links">
<Link to="/">Home</Link>
<Link to="/add">Add Employee</Link>
</div>
Links: The navigation links are wrapped inside a div
with a class of links
. This provides structure and potential styling hooks for the links.
<Link to="/">Home</Link>
Home Link: This Link
component navigates to the home route ("/"
). It displays the text “Home”.
<Link to="/add">Add Employee</Link>
Add Employee Link: This Link
component navigates to the add employee route ("/add"
). It displays the text “Add Employee”.
export default Navbar;
Exporting the Component
The Navbar
component is exported as the default export of the module, allowing it to be imported and used in other parts of the application.
Summary
- Imports: Import React and the
Link
component fromreact-router-dom
. - Component Definition: The
Navbar
functional component returns a JSX structure that defines the navigation bar. - JSX Structure:
- A
nav
element containing the entire navbar. - An
h1
element displaying the application title. - A
div
element containingLink
components for navigation.
- A
- Links: Two
Link
components for navigation:- The Home link (
"/"
). - The Add Employee link (
"/add"
).
- The Home link (
- Export: The
Navbar
component is exported for use in other parts of the application.
Step 5: Creating the Main App Component
Update the main App.js
file to use the Redux Provider and include the necessary routes.
import React from 'react';
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import { Provider } from 'react-redux';
import Navbar from './components/Navbar';
import EmployeeList from './components/EmployeeList';
import AddEmployee from './components/AddEmployee';
import UpdateEmployee from './components/UpdateEmployee';
import ViewEmployee from './components/ViewEmployee';
import DeleteEmployee from './components/DeleteEmployee';
import store from './app/store';
import './App.css';
function App() {
return (
<Provider store={store}>
<Router>
<div className="App">
<Navbar />
<div className="content">
<Routes>
<Route exact path="/" element={<EmployeeList />} />
<Route path="/add" element={<AddEmployee />} />
<Route path="/update/:id" element={<UpdateEmployee />} />
<Route path="/view/:id" element={<ViewEmployee />} />
<Route path="/delete/:id" element={<DeleteEmployee />} />
</Routes>
</div>
</div>
</Router>
</Provider>
);
}
export default App;
Let’s break down the App
component step-by-step to understand its functionality and how it integrates various parts of the application.
import React from 'react';
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import { Provider } from 'react-redux';
import Navbar from './components/Navbar';
import EmployeeList from './components/EmployeeList';
import AddEmployee from './components/AddEmployee';
import UpdateEmployee from './components/UpdateEmployee';
import ViewEmployee from './components/ViewEmployee';
import DeleteEmployee from './components/DeleteEmployee';
import store from './app/store';
import './App.css';
Import Statements
- React: The core React library for building user interfaces.
- BrowserRouter, Route, Routes: Components from
react-router-dom
to handle routing within the application. - Provider: A component from
react-redux
to make the Redux store available to the entire application. - Navbar, EmployeeList, AddEmployee, UpdateEmployee, ViewEmployee, DeleteEmployee: Custom components used in the application.
- store: The Redux store configured in
./app/store
. - App.css: A CSS file for styling the application.
function App() {
return (
<Provider store={store}>
<Router>
<div className="App">
<Navbar />
<div className="content">
<Routes>
<Route exact path="/" element={<EmployeeList />} />
<Route path="/add" element={<AddEmployee />} />
<Route path="/update/:id" element={<UpdateEmployee />} />
<Route path="/view/:id" element={<ViewEmployee />} />
<Route path="/delete/:id" element={<DeleteEmployee />} />
</Routes>
</div>
</div>
</Router>
</Provider>
);
}
export default App;
Component Definition
The App
component is the root component of the application.
JSX Structure
<Provider store={store}>
Explanation
Provider:
The
Provider
component fromreact-redux
is used to make the Redux store available to the entire application. Thestore
is passed as a prop to theProvider
.
<Router>
Router:
- The
Router
component fromreact-router-dom
wraps the entire application to enable routing. Here,BrowserRouter
is used and aliased asRouter
.
<div className="App">
<Navbar />
<div className="content">
<Routes>
<Route exact path="/" element={<EmployeeList />} />
<Route path="/add" element={<AddEmployee />} />
<Route path="/update/:id" element={<UpdateEmployee />} />
<Route path="/view/:id" element={<ViewEmployee />} />
<Route path="/delete/:id" element={<DeleteEmployee />} />
</Routes>
</div>
</div>
Application Structure:
- The application structure is divided into two main parts: the
Navbar
and thecontent
. - The
Navbar
component is included at the top. - The
content
div contains theRoutes
component, which defines the various routes for the application.
<Routes>
<Route exact path="/" element={<EmployeeList />} />
<Route path="/add" element={<AddEmployee />} />
<Route path="/update/:id" element={<UpdateEmployee />} />
<Route path="/view/:id" element={<ViewEmployee />} />
<Route path="/delete/:id" element={<DeleteEmployee />} />
</Routes>
Routes:
- The
Routes
component fromreact-router-dom
contains multipleRoute
components. - Each
Route
defines a path and the component that should be rendered for that path:/
: Renders theEmployeeList
component./add
: Renders theAddEmployee
component./update/:id
: Renders theUpdateEmployee
component, where:id
is a URL parameter./view/:id
: Renders theViewEmployee
component, where:id
is a URL parameter./delete/:id
: Renders theDeleteEmployee
component, where:id
is a URL parameter.
Summary
- Provider: Wraps the entire application with the Redux store.
- Router: Enables routing within the application.
- Navbar: Provides navigation links.
- Routes: Defines the different routes and their corresponding components:
- Home (
/
): Displays the list of employees. - Add Employee (
/add
): Displays the form to add a new employee. - Update Employee (
/update/:id
): Displays the form to update an existing employee. - View Employee (
/view/:id
): Displays the details of a specific employee. - Delete Employee (
/delete/:id
): Handles the deletion of an employee.
- Home (
The App
component serves as the main entry point for the application, setting up routing and providing access to the Redux store throughout the component tree.
Step 6: Styling the App
Ensure the CSS in App.css
matches the design provided in the image.
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
margin: 0;
padding: 0;
}
.navbar {
background-color: #333;
color: #fff;
padding: 10px 20px;
display: flex;
justify-content: space-between;
align-items: center;
}
.navbar h1 {
margin: 0;
}
.navbar .links a {
color: #fff;
margin-left: 20px;
text-decoration: none;
}
.btn {
padding: 5px 10px;
margin: 0 5px;
border: none;
color: #fff;
cursor: pointer;
}
.btn-primary {
background-color: #007bff;
}
.btn-info {
background-color: #17a2b8;
}
.btn-danger {
background-color: #dc3545;
}
.btn-success {
background-color: #28a745;
}
.table {
width: 100%;
margin: 20px 0;
border-collapse: collapse;
}
.table th, .table td {
padding: 10px;
border: 1px solid #ddd;
text-align: left;
}
.table th {
background-color: #f8f8f8;
}
.form-group {
margin: 10px 0;
}
.form-group label {
display: block;
margin-bottom: 5px;
}
.form-group input {
width: 100%;
padding: 8px;
box-sizing: border-box;
}

Welcome to DevTechTutor.com, your ultimate resource for mastering web development and technology! Whether you're a beginner eager to dive into coding or an experienced developer looking to sharpen your skills, DevTechTutor.com is here to guide you every step of the way. Our mission is to make learning web development accessible, engaging, and effective.