Introduction
CRUD stands for Create, Read, Update, and Delete. These four operations are used in many real-world applications to manage data such as users, products, students, and blog posts. React can provide the user interface for CRUD applications, while a backend API or database usually stores the actual data. In this chapter, we will solve practical React CRUD Operations questions using state, forms, API requests, and reusable components. React js CRUD Operations Practice Questions with Solutions to help you understand the concepts.
1. What are CRUD Operations in React?
CRUD stands for:
- Create — Add new data
- Read — Display existing data
- Update — Modify existing data
- Delete — Remove existing data
For example, in a Student Management application:
Create → Add a student
Read → Display students
Update → Edit student details
Delete → Remove a student
React manages the user interface and state, while a backend API commonly handles persistent data.
A simple CRUD flow looks like:
React UI
↓
API Request
↓
Backend
↓
Database
↓
Response
↓
React UI
2. Create Data Using React State
Let’s first create a simple form that adds students to an array in React state.
import { useState } from "react";
function App() {
const [name, setName] = useState("");
const [students, setStudents] = useState([]);
function addStudent(e) {
e.preventDefault();
if (!name.trim()) {
return;
}
const newStudent = {
id: Date.now(),
name: name.trim()
};
setStudents((currentStudents) => [
...currentStudents,
newStudent
]);
setName("");
}
return (
<div>
<h2>Student Management</h2>
<form onSubmit={addStudent}>
<input
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="Student name"
/>
<button type="submit">
Add Student
</button>
</form>
<ul>
{students.map((student) => (
<li key={student.id}>
{student.name}
</li>
))}
</ul>
</div>
);
}
export default App;
Here, the Create operation is performed with:
setStudents((currentStudents) => [
...currentStudents,
newStudent
]);
The spread operator creates a new array instead of directly mutating the existing state array.
3. Read and Display Data from State
The Read operation means displaying existing data.
import { useState } from "react";
function App() {
const [products] = useState([
{
id: 1,
name: "Laptop",
price: 50000
},
{
id: 2,
name: "Keyboard",
price: 2000
}
]);
return (
<div>
<h2>Products</h2>
{products.map((product) => (
<div key={product.id}>
<h3>{product.name}</h3>
<p>Price: ₹{product.price}</p>
</div>
))}
</div>
);
}
export default App;
The important part is:
products.map((product) => ...)
map() creates UI for each product.
Each item uses a stable unique key:
key={product.id}
4. Update Data in React State
The Update operation changes an existing item.
Suppose we want to update a student’s name.
import { useState } from "react";
function App() {
const [students, setStudents] = useState([
{ id: 1, name: "Rahul" },
{ id: 2, name: "Amit" }
]);
function updateStudent(id) {
setStudents((currentStudents) =>
currentStudents.map((student) =>
student.id === id
? { ...student, name: "Rohan" }
: student
)
);
}
return (
<div>
{students.map((student) => (
<div key={student.id}>
<span>{student.name}</span>
<button
onClick={() => updateStudent(student.id)}
>
Update
</button>
</div>
))}
</div>
);
}
export default App;
The map() method creates a new array.
For the matching student:
{
...student,
name: "Rohan"
}
creates a new object with the updated name.
5. Delete Data from React State
The Delete operation removes an item from the data.
We can use filter():
import { useState } from "react";
function App() {
const [students, setStudents] = useState([
{ id: 1, name: "Rahul" },
{ id: 2, name: "Amit" },
{ id: 3, name: "Priya" }
]);
function deleteStudent(id) {
setStudents((currentStudents) =>
currentStudents.filter(
(student) => student.id !== id
)
);
}
return (
<div>
{students.map((student) => (
<div key={student.id}>
<span>{student.name}</span>
<button
onClick={() => deleteStudent(student.id)}
>
Delete
</button>
</div>
))}
</div>
);
}
export default App;
If we call:
deleteStudent(2);
the student with ID 2 is removed.
The original state array is not directly mutated.
6. Create a CRUD Form with Multiple Fields
CRUD applications commonly use forms with multiple fields.
import { useState } from "react";
function App() {
const [form, setForm] = useState({
name: "",
email: ""
});
const [students, setStudents] = useState([]);
function handleChange(e) {
const { name, value } = e.target;
setForm((currentForm) => ({
...currentForm,
[name]: value
}));
}
function handleSubmit(e) {
e.preventDefault();
if (!form.name.trim() || !form.email.trim()) {
return;
}
const student = {
id: Date.now(),
...form
};
setStudents((currentStudents) => [
...currentStudents,
student
]);
setForm({
name: "",
email: ""
});
}
return (
<div>
<form onSubmit={handleSubmit}>
<input
name="name"
value={form.name}
onChange={handleChange}
placeholder="Name"
/>
<input
name="email"
value={form.email}
onChange={handleChange}
placeholder="Email"
/>
<button type="submit">
Add Student
</button>
</form>
{students.map((student) => (
<div key={student.id}>
<h3>{student.name}</h3>
<p>{student.email}</p>
</div>
))}
</div>
);
}
export default App;
The same handleChange() function handles both inputs.
The computed property:
[name]: value
updates the correct field.
7. Fetch Data from a CRUD API
In a real application, data is commonly stored on a server.
We can use fetch() to read data from an API.
import { useEffect, useState } from "react";
function Users() {
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState("");
useEffect(() => {
async function fetchUsers() {
try {
const response = await fetch("/api/users");
if (!response.ok) {
throw new Error("Failed to fetch users");
}
const data = await response.json();
setUsers(data);
} catch (error) {
setError(error.message);
} finally {
setLoading(false);
}
}
fetchUsers();
}, []);
if (loading) {
return <p>Loading users...</p>;
}
if (error) {
return <p>{error}</p>;
}
return (
<div>
<h2>Users</h2>
{users.map((user) => (
<p key={user.id}>
{user.name}
</p>
))}
</div>
);
}
export default Users;
The Read flow is:
Component loads
↓
GET /api/users
↓
Backend sends data
↓
setUsers(data)
↓
Display users
Notice that response.ok is checked because fetch() does not automatically reject its Promise for HTTP errors such as 404 or 500.
8. Create, Update, and Delete Data Using API Requests
A CRUD application can communicate with an API using different HTTP methods.
async function createUser(user) {
const response = await fetch("/api/users", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(user)
});
if (!response.ok) {
throw new Error("Failed to create user");
}
return response.json();
}
For updating:
async function updateUser(id, user) {
const response = await fetch(`/api/users/${id}`, {
method: "PUT",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(user)
});
if (!response.ok) {
throw new Error("Failed to update user");
}
return response.json();
}
For deleting:
async function deleteUser(id) {
const response = await fetch(`/api/users/${id}`, {
method: "DELETE"
});
if (!response.ok) {
throw new Error("Failed to delete user");
}
}
Typical CRUD HTTP methods are:
| Operation | Common HTTP Method |
|---|---|
| Create | POST |
| Read | GET |
| Update | PUT or PATCH |
| Delete | DELETE |
The exact API behavior depends on the backend.
9. Handle Edit Mode in a CRUD Form
A single form can be used for both creating and editing data.
import { useState } from "react";
function App() {
const [name, setName] = useState("");
const [students, setStudents] = useState([
{ id: 1, name: "Rahul" },
{ id: 2, name: "Amit" }
]);
const [editingId, setEditingId] = useState(null);
function handleSubmit(e) {
e.preventDefault();
if (!name.trim()) {
return;
}
if (editingId !== null) {
setStudents((currentStudents) =>
currentStudents.map((student) =>
student.id === editingId
? { ...student, name: name.trim() }
: student
)
);
setEditingId(null);
} else {
setStudents((currentStudents) => [
...currentStudents,
{
id: Date.now(),
name: name.trim()
}
]);
}
setName("");
}
function editStudent(student) {
setName(student.name);
setEditingId(student.id);
}
return (
<div>
<form onSubmit={handleSubmit}>
<input
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="Student name"
/>
<button type="submit">
{editingId !== null
? "Update Student"
: "Add Student"}
</button>
</form>
{students.map((student) => (
<div key={student.id}>
<span>{student.name}</span>
<button
onClick={() => editStudent(student)}
>
Edit
</button>
</div>
))}
</div>
);
}
export default App;
The editingId tells the form whether it is in:
Create Mode
or:
Edit Mode
If editingId is null, a new student is created.
If it contains an ID, the matching student is updated.
10. Build a Practical React CRUD Application
Let’s combine Create, Read, Update, and Delete into one small Student Management application.
import { useState } from "react";
function App() {
const [students, setStudents] = useState([
{
id: 1,
name: "Rahul",
email: "rahul@example.com"
}
]);
const [form, setForm] = useState({
name: "",
email: ""
});
const [editingId, setEditingId] = useState(null);
function handleChange(e) {
const { name, value } = e.target;
setForm((currentForm) => ({
...currentForm,
[name]: value
}));
}
function handleSubmit(e) {
e.preventDefault();
if (!form.name.trim() || !form.email.trim()) {
return;
}
if (editingId !== null) {
setStudents((currentStudents) =>
currentStudents.map((student) =>
student.id === editingId
? {
...student,
name: form.name.trim(),
email: form.email.trim()
}
: student
)
);
setEditingId(null);
} else {
const newStudent = {
id: Date.now(),
name: form.name.trim(),
email: form.email.trim()
};
setStudents((currentStudents) => [
...currentStudents,
newStudent
]);
}
setForm({
name: "",
email: ""
});
}
function editStudent(student) {
setForm({
name: student.name,
email: student.email
});
setEditingId(student.id);
}
function deleteStudent(id) {
setStudents((currentStudents) =>
currentStudents.filter(
(student) => student.id !== id
)
);
}
function cancelEdit() {
setEditingId(null);
setForm({
name: "",
email: ""
});
}
return (
<div>
<h2>Student CRUD Application</h2>
<form onSubmit={handleSubmit}>
<input
name="name"
value={form.name}
onChange={handleChange}
placeholder="Student Name"
/>
<input
name="email"
value={form.email}
onChange={handleChange}
placeholder="Student Email"
/>
<button type="submit">
{editingId !== null
? "Update Student"
: "Add Student"}
</button>
{editingId !== null && (
<button
type="button"
onClick={cancelEdit}
>
Cancel
</button>
)}
</form>
<hr />
{students.map((student) => (
<div key={student.id}>
<h3>{student.name}</h3>
<p>{student.email}</p>
<button
onClick={() => editStudent(student)}
>
Edit
</button>
<button
onClick={() => deleteStudent(student.id)}
>
Delete
</button>
</div>
))}
</div>
);
}
export default App;
How the Application Works
Create
Fill form
↓
Add Student
↓
New student added
Read
students state
↓
map()
↓
Display students
Update
Click Edit
↓
Load data into form
↓
Change details
↓
Update Student
↓
map() updates matching ID
Delete
Click Delete
↓
filter() removes matching ID
↓
Updated list displayed
This example performs CRUD operations locally in React state. In a production application, these operations would normally communicate with a backend API so the data can persist in a database.
Key Takeaways
- CRUD stands for Create, Read, Update, and Delete.
- React can manage CRUD interfaces using state, forms, event handlers, and list rendering.
map()is commonly used to update an item in an array.filter()is commonly used to remove an item from an array.- Spread syntax helps create new arrays and objects instead of directly mutating state.
- Forms are commonly used for Create and Update operations.
fetch()can communicate with backend CRUD APIs.- Common HTTP methods are GET, POST, PUT/PATCH, and DELETE.
response.okshould be checked when usingfetch()because HTTP errors do not automatically reject the Promise.- Real CRUD applications normally store persistent data on a backend/database rather than only in React state.
- Client-side validation improves user experience but does not replace server-side validation.
- Stable unique IDs should be used for React list keys.
FAQs
1. What does CRUD mean in React?
CRUD stands for Create, Read, Update, and Delete. These operations are commonly used to manage application data such as users, products, students, and posts.
2. Can React build a complete CRUD application?
React can build the frontend interface for a CRUD application. Persistent CRUD operations usually require a backend API and database.
3. Which HTTP methods are commonly used for CRUD?
The common mapping is:
- Create → POST
- Read → GET
- Update → PUT or PATCH
- Delete → DELETE
The exact methods supported depend on the backend API.
4. How do I update an array item in React?
map() is commonly used to create a new array and replace the matching item.
setItems((currentItems) =>
currentItems.map((item) =>
item.id === id
? { ...item, name: "Updated" }
: item
)
);
5. How do I delete an item from React state?
filter() can create a new array without the item that should be removed.
setItems((currentItems) =>
currentItems.filter((item) => item.id !== id)
);
6. Should CRUD data be stored only in React state?
React state is useful for displaying and temporarily managing data in the UI, but it is not a database. For persistent application data, a backend and database are normally used.
7. Is fetch() enough for React CRUD operations?
fetch() is enough for making HTTP requests from the browser, but it does not provide a backend or database. A complete CRUD application still needs an API or server that handles data storage and business logic.
Written by Shubhranshu Shekhar, who has trained 20000+ students in coding.
