Skip to main content
React Introduction
CHAPTER 26 Beginner

React CRUD Application

Updated: May 13, 2026
35 min read

# React CRUD Application

1. Introduction

Every software application does four basic things: Create new data, Read existing data, Update existing data, and Delete data. This is famously known as the CRUD pattern. In this chapter, we will tie together everything we've learned—Components, State, Props, Forms, Effects, and API fetching—to build the foundational architecture of a modern web application.

2. Learning Objectives

By the end of this chapter, you will be able to:
  • Combine React Forms with API POST requests to Create data.
  • Use useEffect to Read data on component mount.
  • Send API PUT/PATCH requests to Update data.
  • Send API DELETE requests and update the UI to Delete data.
  • Implement optimistic UI updates for a snappy user experience.

3. Beginner-Friendly Explanations

The Syncing Problem

When you click "Delete" on a task, two things must happen:
  1. 1. The backend database must delete the row.
  1. 2. The frontend React UI must remove the item from the screen.

Pessimistic vs. Optimistic Updates

  • Pessimistic: Click delete -> Show spinner -> Wait for server response -> Re-fetch all tasks to update UI. (Safe, but slow).
  • Optimistic: Click delete -> Instantly remove item from React state (UI updates immediately) -> Send request to server in the background. If the server errors out, revert the UI back. (Feels incredibly fast).

4. Syntax Explanation (The Four API Verbs)

READ (GET Request)

We covered this in Chapter 19. It runs inside a useEffect. ```jsx id="ch26_ex1" const fetchTasks = async () => { const res = await fetch('/api/tasks'); const data = await res.json(); setTasks(data); };
12
### CREATE (POST Request)
Triggered by a form submission.

jsx id="ch26_ex2" const createTask = async (newTaskTitle) => { const res = await fetch('/api/tasks', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ title: newTaskTitle, completed: false }) }); const savedTask = await res.json(); // Update state to include the new task setTasks([...tasks, savedTask]); };

12
### UPDATE (PUT / PATCH Request)
Triggered by an edit form or a toggle button.

jsx id="ch26_ex3" const toggleTask = async (id, currentStatus) => { await fetch(/api/tasks/${id}, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ completed: !currentStatus }) }); // Update local state by mapping through and finding the changed item setTasks(tasks.map(task => task.id === id ? { ...task, completed: !currentStatus } : task )); };

12
### DELETE (DELETE Request)
Triggered by a delete button.

jsx id="ch26_ex4" const deleteTask = async (id) => { await fetch(/api/tasks/${id}, { method: 'DELETE' }); // Update local state by filtering out the deleted item setTasks(tasks.filter(task => task.id !== id)); };

1234567891011121314151617181920
## 5. Output Explanations
Notice how in the `CREATE`, `UPDATE`, and `DELETE` functions, we don't just send the network request; we also call `setTasks`. This manual state manipulation is what makes React SPAs so fast. We don't wait for the server to send us a brand new HTML page; we just update the JavaScript array in memory, and React instantly updates the screen.

## 6. Real-World Examples
- **Twitter:** Create a tweet, Read your timeline, Update (edit) a tweet, Delete a tweet.
- **E-Commerce Admin Panel:** Add a product, View inventory, Update price, Remove product.

## 7. Common Mistakes
- **Forgetting headers in POST requests:** If you send `body: JSON.stringify(data)` without setting `headers: { 'Content-Type': 'application/json' }`, the backend will not understand the data and will likely crash or return a 400 error.
- **Mutating state during updates:** `task.completed = true; setTasks(tasks);`. This is illegal in React. Always use `.map()` to create a brand new array for updates.

## 8. Best Practices
- Separate your API logic into a separate file (e.g., `services/taskApi.js`) so your React component isn't cluttered with `fetch` boilerplate.

## 9. Exercises
1. Write the `fetch` code for a POST request that sends a new `user` object `{ name: "Alex" }` to a mock API endpoint.

## 10. Mini Project: Task Management App (Optimistic UI)
Let's build a functional, beautiful Task App that implements full CRUD in memory (since we don't have a real backend to connect to in this example).

jsx id="ch26_proj1" // Example React component import React, { useState } from 'react';

export default function TaskManager() { // 1. READ: Initial state acts as our database const [tasks, setTasks] = useState([ { id: 1, title: 'Learn React Hooks', completed: true }, { id: 2, title: 'Build a CRUD application', completed: false }, ]); const [newTaskInput, setNewTaskInput] = useState('');

// 2. CREATE const handleAddTask = (e) => { e.preventDefault(); if (!newTaskInput.trim()) return; const newTask = { id: Date.now(), // Generate a fake ID title: newTaskInput, completed: false }; setTasks([...tasks, newTask]); setNewTaskInput(''); // Clear form };

// 3. UPDATE const handleToggleComplete = (id) => { setTasks(tasks.map(task => task.id === id ? { ...task, completed: !task.completed } : task )); };

// 4. DELETE const handleDelete = (id) => { setTasks(tasks.filter(task => task.id !== id)); };

return ( <div className="min-h-screen bg-slate-100 p-8 flex justify-center"> <div className="w-full max-w-xl bg-white shadow-xl rounded-2xl p-8 border border-slate-200"> <h1 className="text-3xl font-black text-slate-800 mb-8">Task Manager</h1>

{/* CREATE Form */} <form onSubmit={handleAddTask} className="flex gap-2 mb-8"> <input type="text" value={newTaskInput} onChange={(e) => setNewTaskInput(e.target.value)} placeholder="What needs to be done?" className="flex-1 px-4 py-3 bg-slate-50 border border-slate-200 rounded-lg focus:ring-2 focus:ring-blue-500 outline-none transition shadow-inner" /> <button type="submit" className="bg-blue-600 hover:bg-blue-700 text-white font-bold px-6 py-3 rounded-lg shadow transition transform hover:scale-105"> Add </button> </form>

{/* READ List */} {tasks.length === 0 ? ( <p className="text-center text-slate-400 italic py-10">No tasks remaining. You're all caught up!</p> ) : ( <ul className="space-y-3"> {tasks.map(task => ( <li key={task.id} className="flex items-center justify-between p-4 bg-white border border-slate-200 rounded-xl hover:shadow-md transition"> {/* UPDATE Checkbox */} <div className="flex items-center gap-4"> <input type="checkbox" checked={task.completed} onChange={() => handleToggleComplete(task.id)} className="w-5 h-5 text-blue-600 cursor-pointer" /> <span className={text-lg ${task.completed ? 'line-through text-slate-400' : 'text-slate-700 font-medium'}}> {task.title} </span> </div>

{/* DELETE Button */} <button onClick={() => handleDelete(task.id)} className="text-red-400 hover:text-red-600 hover:bg-red-50 p-2 rounded transition font-bold" > ✕ </button> </li> ))} </ul> )} </div> </div> ); } ``

11. Coding Challenges

Challenge 1: Add an "Edit" feature to the Task Manager. When a user double-clicks a task's title, replace the
<span> with an <input> field. When they hit enter, save the updated string to the task's title in state.

12. MCQs with Answers

Q1: Which HTTP method is conventionally used to UPDATE existing data? A) GET B) POST C) PATCH / PUT D) DELETE *Answer: C*

Q2: What is the correct way to delete an item with id: 5 from a state array? A) items.splice(5, 1); setItems(items); B) setItems(items.filter(item => item.id !== 5)); C) delete items[5]; *Answer: B*

13. Interview Questions

  • Q: What is the difference between Optimistic and Pessimistic UI updates?
  • Q: Explain how you ensure the UI stays in sync with the database when modifying data.

14. FAQs

Do I always have to manually update state after an API call? If you use native
fetch(), yes. However, if you use modern tools like React Query, it automatically re-fetches the list for you behind the scenes when you trigger a mutation, guaranteeing your UI is always perfectly synced with the database.

15. Summary

Mastering the CRUD flow is the final boss of React basics. By orchestrating forms,
useEffect, state updates (via .map and .filter), and asynchronous fetch` requests, you are now capable of building fully functional, data-driven web applications.

16. Next Chapter Recommendation

You built it. It works on your machine. Now how do you show it to the world? In Chapter 27: React Deployment Basics, we will take your React application and deploy it live to the internet.

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·