React Crud Operations With A Rest Api Complete Guide

 Last Update:2025-06-22T00:00:00     .NET School AI Teacher - SELECT ANY TEXT TO EXPLANATION.    8 mins read      Difficulty-Level: beginner

Understanding the Core Concepts of React CRUD Operations with a REST API

React CRUD Operations with a REST API

Understanding CRUD Operations

  1. Create: Adding new data to the API.
  2. Read: Fetching existing data from the API.
  3. Update: Modifying existing data in the API.
  4. Delete: Removing specified data from the API.

Prerequisites

To effectively perform CRUD operations in React using REST APIs, ensure you have:

  • Node.js & NPM: Essential for running modern JavaScript applications.
  • React: The core library for building UIs.
  • Axios/Fetch: Libraries for making HTTP requests.
  • Backend Server: Running a REST API to handle CRUD requests.
  • State Management: Using tools like React state or context/redux for maintaining the app's state.

Setting Up The Project

Before diving into operations, set up your React project:

npx create-react-app react-crud-app
cd react-crud-app

Install Axios to facilitate HTTP requests:

npm install axios

Set up your backend REST API (using Node.js/Express for example):

mkdir backend && cd backend
npm init -y
npm install express cors body-parser mongoose

Create an Express server with basic CRUD endpoints.

Create Operation

In your React application, create a form component where users can input data and submit it to the server:

// Import statements
import React, { useState } from 'react';
import axios from 'axios';

function CreateItem() {
  const [name, setName] = useState('');
  const [price, setPrice] = useState('');

  const handleSubmit = async (e) => {
    e.preventDefault();
    const newItem = { name, price };
    try {
      await axios.post('http://localhost:5000/api/items', newItem);
      setName('');
      setPrice('');
      // Additional logic to update state or notify the user
    } catch (error) {
      console.error(error);
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <input type="text" value={name} onChange={(e) => setName(e.target.value)} placeholder="Name" />
      <input type="number" value={price} onChange={(e) => setPrice(e.target.value)} placeholder="Price" />
      <button type="submit">Create</button>
    </form>
  );
}

Read Operation

Create a component to fetch and display items from the API:

// Import statements
import React, { useEffect, useState } from 'react';
import axios from 'axios';

function ItemList() {
  const [items, setItems] = useState([]);

  useEffect(() => {
    const fetchItems = async () => {
      try {
        const response = await axios.get('http://localhost:5000/api/items');
        setItems(response.data);
      } catch (error) {
        console.error(error);
      }
    };

    fetchItems();
  }, []);

  return (
    <div>
      <h2>Items List</h2>
      <ul>
        {items.map(item => (
          <li key={item._id}>{item.name}: ${item.price}</li>
        ))}
      </ul>
    </div>
  );
}

Update Operation

To enable updating, create a form to modify existing items:

// Import statements
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import { useParams, useNavigate } from 'react-router-dom';

function EditItem() {
  const { id } = useParams();
  const navigate = useNavigate();
  const [name, setName] = useState('');
  const [price, setPrice] = useState('');

  useEffect(() => {
    const fetchItem = async () => {
      try {
        const response = await axios.get(`http://localhost:5000/api/items/${id}`);
        setName(response.data.name);
        setPrice(response.data.price);
      } catch (error) {
        console.error(error);
      }
    };

    fetchItem();
  }, [id]);

  const handleSubmit = async (e) => {
    e.preventDefault();
    const updatedItem = { name, price };
    try {
      await axios.put(`http://localhost:5000/api/items/${id}`, updatedItem);
      navigate('/');
    } catch (error) {
      console.error(error);
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <input type="text" value={name} onChange={(e) => setName(e.target.value)} placeholder="Edit Name" />
      <input type="number" value={price} onChange={(e) => setPrice(e.target.value)} placeholder="Edit Price" />
      <button type="submit">Update</button>
    </form>
  );
}

Ensure your backend supports GET and PUT requests:

// Backend route to fetch a single item
app.get('/api/items/:id', async (req, res) => {
  try {
    const item = await Item.findById(req.params.id);
    res.json(item);
  } catch (error) {
    res.status(404).send();
  }
});

// Backend route to update an item
app.put('/api/items/:id', async (req, res) => {
  try {
    const item = await Item.findByIdAndUpdate(req.params.id, req.body, { new: true });
    res.json(item);
  } catch (error) {
    res.status(404).send();
  }
});

Delete Operation

Implement delete functionality within your React application:

// Import statements
import React, { useEffect, useState } from 'react';
import axios from 'axios';
import { useNavigate } from 'react-router-dom';

function ItemList() {
  const [items, setItems] = useState([]);
  const navigate = useNavigate();

  useEffect(() => {
    const fetchItems = async () => {
      try {
        const response = await axios.get('http://localhost:5000/api/items');
        setItems(response.data);
      } catch (error) {
        console.error(error);
      }
    };

    fetchItems();
  }, []);

  const handleDelete = async (id) => {
    try {
      await axios.delete(`http://localhost:5000/api/items/${id}`);
      setItems(items.filter(item => item._id !== id));
    } catch (error) {
      console.error(error);
    }
  };

  return (
    <div>
      <h2>Items List</h2>
      <ul>
        {items.map(item => (
          <li key={item._id}>{item.name}: ${item.price} <button onClick={() => handleDelete(item._id)}>Delete</button></li>
        ))}
      </ul>
    </div>
  );
}

Your backend should support DELETE requests as well:

// Backend route to delete an item
app.delete('/api/items/:id', async (req, res) => {
  try {
    await Item.findByIdAndDelete(req.params.id);
    res.status(200).send();
  } catch (error) {
    res.status(404).send();
  }
});

Routing with React Router

Manage navigation between pages using React Router. Install it first:

npm install react-router-dom

Then set up routes:

// Import statements
import React from 'react';
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import CreateItem from './components/CreateItem';
import ItemList from './components/ItemList';
import EditItem from './components/EditItem';

function App() {
  return (
    <Router>
      <Routes>
        <Route path="/" element={<ItemList />} />
        <Route path="/create" element={<CreateItem />} />
        <Route path="/edit/:id" element={<EditItem />} />
      </Routes>
    </Router>
  );
}

export default App;

State Management

Use React’s built-in state management (useState, useEffect) for small apps. For larger applications, consider using context API or Redux for efficient and manageable state handling.

// Context provider setup (simplified)
const ItemContext = createContext();

function App() {
  const [items, setItems] = useState([]);

  const addItem = (item) => {
    setItems([...items, item]);
  }

  const removeItem = (id) => {
    setItems(items.filter(item => item._id !== id));
  }

  return (
    <ItemContext.Provider value={{ items, addItem, removeItem }}>
      <Router>
        <Routes>
          <Route path="/" element={<ItemList />} />
          <Route path="/create" element={<CreateItem />} />
          <Route path="/edit/:id" element={<EditItem />} />
        </Routes>
      </Router>
    </ItemContext.Provider>
  );
}

Error Handling

Always include error handling to manage API failures gracefully:

Online Code run

🔔 Note: Select your programming language to check or run code at

💻 Run Code Compiler

Step-by-Step Guide: How to Implement React CRUD Operations with a REST API

Prerequisites

  • Basic knowledge of React.
  • Node.js and npm installed on your machine.
  • A text editor or an IDE (Visual Studio Code is recommended).

Step 1: Set up the React Application

First, create a new React application using Create React App.

npx create-react-app react-crud-example
cd react-crud-example

Step 2: Install Axios

Axios is a promise-based HTTP client for the browser and Node.js, which will be used to make HTTP requests.

npm install axios

Step 3: Create Components

Create the necessary components for our CRUD operations. For this example, we will create four components:

  • App: Main component.
  • Posts: Lists all posts.
  • PostForm: Form to create and update posts.
  • PostItem: Individual post details.

Create the following structure under the src folder:

src/
├── App.js
├── components/
│   ├── Posts.js
│   ├── PostForm.js
│   └── PostItem.js
└── App.css

Step 4: Implement App.js

App.js will contain the main logic and state management for our application.

// src/App.js
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import Posts from './components/Posts';
import PostForm from './components/PostForm';

function App() {
  const [posts, setPosts] = useState([]);
  const [loading, setLoading] = useState(true);
  const [currentPost, setCurrentPost] = useState(null);

  useEffect(() => {
    fetchPosts();
  }, []);

  const fetchPosts = async () => {
    try {
      const res = await axios.get('https://jsonplaceholder.typicode.com/posts');
      setPosts(res.data);
      setLoading(false);
    } catch (error) {
      console.error('Error fetching posts:', error);
      setLoading(false);
    }
  };

  const addPost = async (postData) => {
    try {
      const res = await axios.post('https://jsonplaceholder.typicode.com/posts', postData);
      setPosts([...posts, res.data]);
    } catch (error) {
      console.error('Error adding post:', error);
    }
  };

  const updatePost = async (postId, postData) => {
    try {
      const res = await axios.put(`https://jsonplaceholder.typicode.com/posts/${postId}`, postData);
      setPosts(posts.map(post => (post.id === postId ? res.data : post)));
      setCurrentPost(null);
    } catch (error) {
      console.error('Error updating post:', error);
    }
  };

  const deletePost = async (postId) => {
    try {
      await axios.delete(`https://jsonplaceholder.typicode.com/posts/${postId}`);
      setPosts(posts.filter(post => post.id !== postId));
    } catch (error) {
      console.error('Error deleting post:', error);
    }
  };

  return (
    <div className="App">
      <h1>React CRUD Example</h1>
      <PostForm addPost={addPost} updatePost={updatePost} currentPost={currentPost} setCurrentPost={setCurrentPost} />
      {loading ? (
        <p>Loading...</p>
      ) : (
        <Posts posts={posts} deletePost={deletePost} setCurrentPost={setCurrentPost} />
      )}
    </div>
  );
}

export default App;

Step 5: Implement Posts.js

Posts.js will render the list of posts and have a delete button for each post.

// src/components/Posts.js
import React from 'react';
import PostItem from './PostItem';

function Posts({ posts, deletePost, setCurrentPost }) {
  return (
    <div>
      <h2>Posts</h2>
      <ul>
        {posts.map(post => (
          <PostItem key={post.id} post={post} deletePost={deletePost} setCurrentPost={setCurrentPost} />
        ))}
      </ul>
    </div>
  );
}

export default Posts;

Step 6: Implement PostItem.js

PostItem.js will render the individual post details and provide options to delete or edit the post.

// src/components/PostItem.js
import React from 'react';

function PostItem({ post, deletePost, setCurrentPost }) {
  return (
    <li>
      <h3>{post.title}</h3>
      <p>{post.body}</p>
      <button onClick={() => setCurrentPost(post)}>Edit</button>
      <button onClick={() => deletePost(post.id)}>Delete</button>
    </li>
  );
}

export default PostItem;

Step 7: Implement PostForm.js

PostForm.js will have a form for adding and updating posts.

// src/components/PostForm.js
import React, { useState, useEffect } from 'react';

function PostForm({ addPost, updatePost, currentPost, setCurrentPost }) {
  const [title, setTitle] = useState('');
  const [body, setBody] = useState('');

  useEffect(() => {
    if (currentPost) {
      setTitle(currentPost.title);
      setBody(currentPost.body);
    } else {
      setTitle('');
      setBody('');
    }
  }, [currentPost]);

  const handleSubmit = (e) => {
    e.preventDefault();

    if (currentPost) {
      updatePost(currentPost.id, { title, body });
    } else {
      addPost({ title, body });
    }

    setTitle('');
    setBody('');
    setCurrentPost(null);
  };

  return (
    <div>
      <h2>{currentPost ? 'Edit Post' : 'Add Post'}</h2>
      <form onSubmit={handleSubmit}>
        <input
          type="text"
          placeholder="Title"
          value={title}
          onChange={(e) => setTitle(e.target.value)}
          required
        />
        <textarea
          placeholder="Body"
          value={body}
          onChange={(e) => setBody(e.target.value)}
          required
        />
        <button type="submit">{currentPost ? 'Update' : 'Add'}</button>
        {currentPost && <button onClick={() => setCurrentPost(null)}>Cancel</button>}
      </form>
    </div>
  );
}

export default PostForm;

Step 8: Run the Application

Now run your application using the following command:

npm start

This should start the development server and open your new React CRUD application in the browser.

Step 9: Testing CRUD Operations

  • Create: Fill out the form and click "Add" to create a new post.
  • Read: View all the posts listed below the form.
  • Update: Click "Edit" on a post to modify its details and click "Update" to save the changes.
  • Delete: Click "Delete" to remove a post.

Conclusion

Top 10 Interview Questions & Answers on React CRUD Operations with a REST API

1. What are the basic steps to implement CRUD operations in a React application using REST APIs?

Answer: The fundamental steps involve setting up the environment, defining components to handle each CRUD operation, and leveraging HTTP methods like GET, POST, PUT, and DELETE via fetch or an HTTP library such as Axios. Here’s a breakdown:

  • Set Up: Initialize your project with Create React App.
  • Components: Design components such as Form for Create and Update, List for Read, and DeleteButton for Delete.
  • State Management: Use React hooks (useState, useEffect) to manage the state of data and side effects.
  • HTTP Requests:
    • Read (GET): Fetch data when the component mounts using useEffect.
    • Create (POST): Send new data to the server when the form is submitted.
    • Update (PUT/PATCH): Modify existing data by sending updated information typically when a form is edited and resubmitted.
    • Delete (DELETE): Remove a specific entry from the database when the delete button is clicked or some condition is met.

2. How do you fetch data from a REST API in React?

Answer: Typically, data fetching is handled within the useEffect hook to ensure that the data load occurs after the initial render.

import React, { useState, useEffect } from 'react';
import axios from 'axios';

function UserList() {
    const [users, setUsers] = useState([]);

    useEffect(() => {
        fetchUsers();
    }, []);

    async function fetchUsers() {
        try {
            const response = await axios.get('https://api.example.com/users');
            setUsers(response.data);
        } catch (error) {
            console.error('Failed to fetch users:', error);
        }
    }

    return (
        <div>
            {users.map(user => (
                <div key={user.id}>{user.name}</div>
            ))}
        </div>
    );
}

3. How can you implement data filtering/sorting/searching in a list fetched from a REST API?

Answer: Implement filtering/sorting/searching by handling state for user input and applying this logic to modify what gets rendered without needing additional API requests.

function UserList({ users }) {
    const [searchTerm, setSearchTerm] = useState('');

    const filteredUsers = users.filter(user => 
        user.name.toLowerCase().includes(searchTerm.toLowerCase())
    );

    return (
        <div>
            <input 
                type="text" 
                placeholder="Search Name" 
                value={searchTerm} 
                onChange={e => setSearchTerm(e.target.value)}
            />
            {filteredUsers.map(user => (
                <div key={user.id}>{user.name}</div>
            ))}
        </div>
    );
}

For more complex scenarios, consider debouncing searches and loading only necessary data on demand (server-side filtering and sorting).

4. How should you manage form states for creating and updating records?

Answer: Manage form states using hooks such as useState. Reset the state upon successful form submission.

function UserForm({ onSubmit }) {
    const [name, setName] = useState('');
    const [email, setEmail] = useState('');

    const handleSubmit = (e) => {
        e.preventDefault();
        onSubmit({ name, email });
        setName('');
        setEmail('');
    };

    return (
        <form onSubmit={handleSubmit}>
            <input 
                type="text" 
                value={name} 
                onChange={e => setName(e.target.value)} 
                placeholder="Name"
            />
            <input 
                type="email" 
                value={email} 
                onChange={e => setEmail(e.target.value)} 
                placeholder="Email"
            />
            <button type="submit">Submit</button>
        </form>
    );
}

5. What HTTP method should be used to create and update resources?

Answer: Use POST to create resources and PUT or PATCH to update them.

  • Create (POST):
async function createUser(user) {
    try {
        const response = await axios.post('https://api.example.com/users', user);
        setUsers(prevUsers => [...prevUsers, response.data]);
    } catch (error) {
        console.error('Failed to create user:', error);
    }
}
  • Update (PUT/PATCH):
async function updateUser(id, updatedData) {
    try {
        await axios.put(`https://api.example.com/users/${id}`, updatedData);
        setUsers(prevUsers => 
            prevUsers.map(user => (user.id === id ? updatedData : user))
        );
    } catch (error) {
        console.error('Failed to update user:', error);
    }
}

6. How do you handle errors gracefully during CRUD operations?

Answer: Wrap your API calls in try-catch blocks to handle any exceptions thrown. Provide feedback to the user with error messages or status alerts.

async function deleteUser(userId) {
    try {
        await axios.delete(`https://api.example.com/users/${userId}`);
        setUsers(prevUsers => prevUsers.filter(user => user.id !== userId));
    } catch (error) {
        alert('Failed to delete user.');
        console.error(error);
    }
}

7. How can you implement optimistic updates in React applications for a better user experience?

Answer: Optimistic UI updates involve reflecting changes immediately in the UI before confirming that the server has accepted the change. This makes the app feel responsive.

Example (for a delete operation):

const handleDeleteClick = () => {
    // Optimistically remove the item
    setUsers(users.filter(user => user.id !== userId));
    deleteUser(userId); // async API call to server
};

8. Can you provide an example of how to paginate data in React applications when using REST APIs?

Answer: Implement pagination by including page and limit query parameters in your API request.

const [page, setPage] = useState(1);
const [hasMore, setHasMore] = useState(true);

useEffect(() => {
    fetchUsers(page);
}, [page]);

const fetchUsers = async (pageNumber) => {
    try {
        const response = await axios.get(`https://api.example.com/users?page=${pageNumber}&limit=10`);
        if (response.data.length === 0) setHasMore(false);
        
        setUsers(prevUsers => [...prevUsers, ...response.data]);
    } catch (err) {
        console.log(err);
        setHasMore(false);
    }
}; 

Include buttons or controls to navigate between pages.

9. How can you ensure that your forms are always validated before submitting them to the server?

Answer: Validate form inputs in real-time or upon submission before making the API call. Use libraries like Formik and Yup for easier validation.

import * as Yup from 'yup';
import { useFormik } from 'formik';

function UserForm({ onSubmit }) {
    const formik = useFormik({
        initialValues: {
            name: '',
            email: ''
        },
        validationSchema: Yup.object({
            name: Yup.string().required('Required'),
            email: Yup.string().email('Invalid email address').required('Required'),
        }),
        onSubmit: values => {
            onSubmit(values);
        },
    });

    return (
        <form onSubmit={formik.handleSubmit}>
            <input 
                type="text" 
                {...formik.getFieldProps('name')}
            />
            {formik.touched.name && formik.errors.name ? <div>{formik.errors.name}</div> : null}
            <input 
                type="email" 
                {...formik.getFieldProps('email')}
            />
            {formik.touched.email && formik.errors.email ? <div>{formik.errors.email}</div> : null}
            <button type="submit">Submit</button>
        </form>
    );
}

10. What are some best practices to follow when working with CRUD operations and REST APIs in React?

Answer:

  • API Rate Limiting: Be aware of server rate limits. Avoid excessive API calls in rapid succession.
  • Asynchronous Flow: Handle asynchronous operations cleanly. Use async/await and keep promises in control.
  • State Updates: Always ensure that state updates (like appending new items after creation) don’t interfere with ongoing fetch operations.
  • Security: Protect sensitive data. Use environment variables for keeping API keys secure. Avoid making direct API requests from the client-side that require such keys unless absolutely necessary.
  • Error Handling: Implement extensive error handling and user feedback mechanisms. Let users know what went wrong and how they can fix it.
  • Optimizations: Utilize optimistic UI updates and lazy loading where appropriate to improve performance and user experience.
  • Testing: Write unit tests for your components and integration tests for your CRUD functionalities. Libraries like Jest and React Testing Library can help.
  • Reusable Components: Create reusable components and utility functions to avoid redundancy and improve maintainability.

You May Like This Related .NET Topic

Login to post a comment.