React CRUD App Tutorial with MUI 5

Building a basic CRUD (Create, Read, Update, Delete) app in React with Material UI (MUI) version 5 requires a series of steps. Here’s an illustration of creating such an app within a single page. While this example covers the essential components for CRUD operations, it doesn’t encompass advanced functionalities like API integration or error handling.

Install & Setup Vite + React + Typescript + MUI 5

React MUI 5 Simple CRUD App

Splitting your CRUD application into separate components is a good practice for maintainability and readability. Here’s an example of how you can split the previous single-page application into multiple components:

1. App Component: The main component that will render other components.

2. AddItemForm: A component for adding new items.

3. EditItemForm: A component for editing existing items.

4. ItemsTable: A component to display the list of items.

App Component
import { useState } from 'react';
import { Container } from '@mui/material';
import AddItemForm from './AddItemForm';
import EditItemForm from './EditItemForm';
import ItemsTable from './ItemsTable';

function App() {
  const [items, setItems] = useState([]);
  const [editing, setEditing] = useState(false);
  const [currentItem, setCurrentItem] = useState({ id: null, name: '' });

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

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

  const updateItem = (id, updatedItem) => {
    setEditing(false);
    setItems(items.map(item => (item.id === id ? updatedItem : item)));
  };

  const editRow = item => {
    setEditing(true);
    setCurrentItem({ id: item.id, name: item.name });
  };

  return (
    <Container>
      <h1>CRUD App with React</h1>
      {editing ? (
        <EditItemForm
          editing={editing}
          setEditing={setEditing}
          currentItem={currentItem}
          updateItem={updateItem}
        />
      ) : (
        <AddItemForm addItem={addItem} />
      )}
      <ItemsTable items={items} editRow={editRow} deleteItem={deleteItem} />
    </Container>
  );
}

export default App;

AddItemForm Component

import { useState } from 'react';
import { TextField, Button } from '@mui/material';

const AddItemForm = props => {
  const initialFormState = { id: null, name: '' };
  const [item, setItem] = useState(initialFormState);

  const handleInputChange = event => {
    const { name, value } = event.target;
    setItem({ ...item, [name]: value });
  };

  return (
    <form
      onSubmit={event => {
        event.preventDefault();
        if (!item.name) return;
        props.addItem(item);
        setItem(initialFormState);
      }}
    >
      <TextField name="name" size="small" label="Name" value={item.name} onChange={handleInputChange} />
      <Button type="submit"  variant="contained">Add new item</Button>
    </form>
  );
};

export default AddItemForm;

EditItemForm Component

import { useState, useEffect } from 'react';
import { TextField, Button } from '@mui/material';

const EditItemForm = props => {
  const [item, setItem] = useState(props.currentItem);

  useEffect(() => {
    setItem(props.currentItem);
  }, [props]);

  const handleInputChange = event => {
    const { name, value } = event.target;
    setItem({ ...item, [name]: value });
  };

  return (
    <form
      onSubmit={event => {
        event.preventDefault();
        props.updateItem(item.id, item);
      }}
    >
      <TextField name="name" size="small" label="Name" value={item.name} onChange={handleInputChange} />
      <Button type="submit" variant="contained">Update item</Button>
      <Button onClick={() => props.setEditing(false)}>Cancel</Button>
    </form>
  );
};

export default EditItemForm;

ItemsTable Component

import { Table, TableBody, TableCell, TableHead, TableRow, Button } from '@mui/material';

const ItemsTable = props => {
  return (
    <Table>
      <TableHead>
        <TableRow>
          <TableCell>ID</TableCell>
          <TableCell>Name</TableCell>
          <TableCell>Actions</TableCell>
        </TableRow>
      </TableHead>
      <TableBody>
        {props.items.length > 0 ? (
          props.items.map(item => (
            <TableRow key={item.id}>
              <TableCell>{item.id}</TableCell>
              <TableCell>{item.name}</TableCell>
              <TableCell>
                <Button onClick={() => props.editRow(item)}>Edit</Button>
                <Button onClick={() => props.deleteItem(item.id)}>Delete</Button>
              </TableCell>
            </TableRow>
          ))
        ) : (
          <TableRow>
            <TableCell colSpan={3}>No items</TableCell>
          </TableRow>
        )}
      </TableBody>
    </Table>
  );
};

export default ItemsTable;
crud app
Aaronn
Aaronn

Hey there! I'm Aaronn, a Full Stack Developer who's all about React, NEXTJS, Node.js, and Tailwind CSS. I'm on a mission to craft awesome websites that look great and work even better.