Update in React.js CRUD Operations

Introduction

In my preceding article, I delved into the 'Create' operation within React.js CRUD operations, emphasizing its pivotal role in effective data management. This comprehensive guide offers practical insights into the creation of forms, the adept handling of form submissions, and the transmission of form data via Post using Axios. The aim is to ensure a fluid and user-friendly experience within React applications.

  1. Create in React.js CRUD Operations
  2. Read in React.js CRUD Operations
  3. MVC Architecture With Node.js CRUD Application [Node.js-Express-MongoDB]

In my previous article (Create in React.js CRUD Operations) I explain creating a form with Submitting Form Data and Handling Success.

Student management system

Picture 1. Submitting Form Data.

Let’s continue our Topic 

Introduction Update(U)

"Update" refers to the process of modifying or altering existing data in a system...

Update operation

Identification of Data: Before updating any data, you need to identify the specific record or set of records that you want to modify. This typically involves querying the system to retrieve the existing data.

Modification of Data: Once the data to be updated is identified, you can make the necessary changes. This might involve editing one or more fields within a record.

Persistence of Changes: After making the modifications, the changes need to be persisted in the underlying data storage, whether it's a database, file system, or another form of data storage.

In a web application using a framework like React.js, the update operation might involve interacting with a server-side API to send the updated data and then updating the user interface to reflect the changes.

Student data

Picture 2. Student management system Update operation.

Let’s start the update operation with practical.

SMS

Picture 3.  In this table view, there are two buttons Edit and Delete.

Let’s Start The Edit Step By Step

You might implement an 'Edit' functionality in a React student management system. In this example, let's assume you have a list of students, and you wish to edit the details of a specific student when the 'Edit' button is clicked.

Step 1. Get the Student ID

1. Go to the student.js page and create two variables editID and setEditID.

const [editID, setEditID] = useState();

2. Create an arrow function as handleClickEdit. This function takes one parameter, row_id.

  const handleClickEdit = (row_id) => {
    setEditID(row_id);
    console.log("handle Click Edit ID", row_id);
  };

The purpose of this function is to update or set the value of an identifier called EditID with the value of the provided row_id.

3. DataTable component and passing two props: data (the data to be displayed in the table) and handleClickEdit (a function to be called when a certain action, like clicking on a row, occurs).

<DataTable data={data}  handleClickEdit={handleClickEdit} />

4. Go to the tabel.js page and add this destructuring parameter.

const Table = ({ data, handleClickEdit }) => {}

This is an arrow function with destructuring in its parameter list. It's a concise way to define a functional component that receives props. In this case, the component expects two props: data and handleClickEdit.

5. Go to the Edit Button and create an Onclick function.

   <button style={{ marginRight: '8px' }}
                  size="small"
                  variant="outlined"
                   onClick={() => handleClickEdit(row._id)}>
                  Edit
                </button>

When clicked, it triggers the handleClickEdit function with the row._id as an argument, which is likely used for handling the edit action associated with the corresponding row in a table or list.

Console

 Picture 4.  When I click the edit button get the Student ID by console.

Step 2: Form Load The Specific Data

Edit the details of a specific student when the 'Edit' button is clicked.

1. Go to the student.js page and create two variables FormSubmitted, setFormSubmitted.

 const [FormSubmitted, setFormSubmitted] = useState(0);

2. MyForm component and passing two props to it: editID and setFormSubmitted.

<MyForm  editID={editID} setFormSubmitted={setFormSubmitted} />

These props are used by the MyForm component to customize its behavior based on the editID and to communicate with the parent component through the setFormSubmitted function.

3. Go to the student form.JSX page

const MyForm = ({ editID, setFormSubmitted }) => {}

Destructuring in its parameter list. In this case, the component expects two props: editID and setFormSubmitted.

4. Create an arrow function to fetch data by id.

const fetchData = async (id) => {
    try {
      const response = await axios.get(
        `http://localhost:5000/api/student/${id}`
      );
      console.log("Record edited:", response.data);
      const date = new Date(response.data.dateOfBirth);
      const formattedDate = date.toLocaleDateString("en-US");
      const newData = { ...response.data, dateOfBirth: formattedDate };
      console.log("newData >>>>>", newData);
      setFormData(newData);
    } catch (error) {
      console.error("Error fetching data:", error);
    }
  };
  •  This defines an asynchronous function named fetchData that takes an id parameter. And sends an HTTP GET request to the specified URL(http://localhost:5000/api/student/${id}) using the Axios library.

Date Formatting

  • const date = new Date(response.data.dateOfBirth): Creates a JavaScript Date object from the dateOfBirth field of the response data.
  • const formattedDate: date.toLocaleDateString("en-US"): Converts the date to a formatted string using the toLocaleDateString method with the "en-US" locale.
  • const newData: { ...response.data, dateOfBirth: formattedDate }: Creates a new object (newData) by spreading the properties of the response data and replacing the dateOfBirth property with the formatted date.
  • setFormData(newData): Sets the state of the component using the setFormData function. This likely updates the component's state with the new data, triggering a re-render with the updated information.

5. Use the useEffect hook in React.

  useEffect(() => {
    if (editID) {
      fetchData(editID);
    }  }, [editID]);

Purpose of this useEffect hook is to trigger the fetchData function when the editID dependency changes. This is commonly used in React to perform side effects, such as fetching data from an API, when certain conditions or dependencies change. In this case, it appears to be fetching data when the editID changes, assuming that fetchData is a function responsible for fetching data based on the provided editID.

Filter

 Picture 5. When the 'Edit' button is clicked, retrieve the student details by ID, and load the form with the data obtained from the student details.

Step 3. Updating Edited Form Data

1. Submit Data: After the user has made the necessary edits, they submit the form. This typically involves clicking a "Submit" button. When the form is submitted, the data entered by the user is sent to the server for processing.

Got to the student form.JSX page and create two variables isEdit, setIsEdit.

const [isEdit, setIsEdit] = useState(false);

2. If the “editID” is available, enable Edit Mode. add setIsEdit(true)inside of If condition.

useEffect(() => {
    if (editID) {
      // Fetch data if editID is provided (edit mode)
      setIsEdit(true);
      fetchData(editID);
    } else {
      setIsEdit(false);
    }
  }, [editID]);

Set the values true in setIsEdit.

3. Handling the logic for Updating a record.

  if (isEdit) {
        // Handle edit logic, make a PUT request
        const response = await axios
          .put(`http://localhost:5000/api/student/${editID}`, formData)
          .then((response) => {
            console.log("Record edited:", response.data);
            setSuccessMessage("Data Updated successfully!");
            setTimeout(() => {
              setSuccessMessage("");
            }, 3000);
            setFormData(initialValues);
            setIsEdit(false);
          })
          .then((error) => {
            console.error("Error:", error);
          });
      }
  • if (isEdit) { ... }: This condition checks whether the variable isEdit is true. If isEdit is true, it means the form is in edit mode.
  • await Axios.put(`http://localhost:5000/api/student/${editID}`, formData)

an asynchronous HTTP PUT request to update a student record. The URL is dynamically constructed based on the  ${editID} editID, and the data to be updated is provided in the formData.

  • setSuccessMessage("Data Updated successfully!"): Sets a success message, presumably for display in the user interface.
  • setTimeout(() => { setSuccessMessage(""); }, 3000): Clears the success message after a delay of 3000 milliseconds (3 seconds).
  • setFormData(initial_values): Resets the form data to initial values, possibly to clear the form after successful submission.
  • setIsEdit(false): Sets isEdit to false, indicating that the form is no longer in edit mode.

student.js page

import React, { useState, useEffect } from "react";
import axios from "axios";
import MyForm from "../component/studentForm";
import DataTable from "../component/table";

export default function Student() {
  const [data, setData] = useState([]);

  const [editID, setEditID] = useState();
  const [FormSubmitted, setFormSubmitted] = useState(0);

  useEffect(() => {
    fetchStudentData();
  }, [FormSubmitted]);

  const fetchStudentData = async () => {
    const res = await axios.get("http://localhost:5000/api/student");
    setData(res.data);
  };

  const handleClickEdit = (row_id) => {
    setEditID(row_id);
    console.log("<<<<<Edit ID>>>>>", row_id);
  };

  return (
    <div className="App">
      <h1> Student Management System</h1>
      <MyForm  editID={editID} setFormSubmitted={setFormSubmitted} />
      <DataTable data={data} handleClickEdit={handleClickEdit} />
    </div>
  );
}

student form.JSX page

import axios from "axios";
import React, { useState, useEffect } from "react";
import "./style.css"; // Import the CSS file

const MyForm = ({ editID, setFormSubmitted }) => {
  const initialValues = {
    name: "",
    address: "",
    dateOfBirth: "",
    gender: "",
    phoneNum: "",
  };
  const [formData, setFormData] = useState(initialValues);
  const [successMessage, setSuccessMessage] = useState("");
  const [errorsMessage, setErrorsMessage] = useState("");
  const [formErrors, setFormErrors] = useState({
    name: "",
    address: "",
    dateOfBirth: "",
    gender: "",
    phoneNum: "",
  });
  const [isEdit, setIsEdit] = useState(false);

  useEffect(() => {
    if (editID) {
      // Fetch data if editID is provided (edit mode)
      setIsEdit(true);
      fetchData(editID);
    } else {
      setIsEdit(false);
    }
  }, [editID]);

  const fetchData = async (id) => {
    try {
      const response = await axios.get(
        `http://localhost:5000/api/student/${id}`
      );
      console.log("Record edited:", response.data);
      const date = new Date(response.data.dateOfBirth);
      const formattedDate = date.toLocaleDateString("en-US");
      const newData = { ...response.data, dateOfBirth: formattedDate };
      console.log("newData >>>>>", newData);
      setFormData(newData);
    } catch (error) {
      console.error("Error fetching data:", error);
    }
  };

  const handleChange = (e) => {
    const { name, value } = e.target;
    setFormData((prevData) => ({
      ...prevData,
      [name]: value,
    }));
    setErrorsMessage(" ");
    // You can add validation here and update formErrors state accordingly
    validateField(name, value);
  };

  const validateField = (name, value) => {
    // Basic validation, you can customize this based on your requirements
    switch (name) {
      case "name":
        setFormErrors((prevErrors) => ({
          ...prevErrors,
          name:
            value.length < 3 ? "Name must be at least 3 characters long" : "",
        }));
        break;
      case "address":
        setFormErrors((prevErrors) => ({
          ...prevErrors,
          name: value.length < 5 ? "Address is Require" : "",
        }));
        break;
      case "dateOfBirth":
        setFormErrors((prevErrors) => ({
          ...prevErrors,
          name: value.length === 0 ? "Date Of Birth is Require" : "",
        }));
        break;
      case "gender":
        setFormErrors((prevErrors) => ({
          ...prevErrors,
          name: value === "" ? "Gender is Require Please Select" : "",
        }));
        break;
      case "phoneNum":
        setFormErrors((prevErrors) => ({
          ...prevErrors,
          name:
            value.length < 8
              ? "Phone Number must be at least 8 characters long"
              : "",
        }));
        break;
      default:
        break;
    }
  };

  const handleSubmit = async (e) => {
    e.preventDefault();
    // if (!formErrors) {}   else {
    //   setErrorsMessage("Please enter all fields; all are required ");
    // }
    try {
      if (isEdit) {
        // Handle edit logic, make a PUT request
        const response = await axios
          .put(`http://localhost:5000/api/student/${editID}`, formData)
          .then((response) => {
            console.log("Record edited:", response.data);
            setSuccessMessage("Data Updated successfully!");
            setTimeout(() => {
              setSuccessMessage("");
            }, 6000);
            setFormData(initialValues);
            setIsEdit(false);
          })
          .then((error) => {
            console.error("Error:", error);
          });
      } else {
        const res = await axios
          .post("http://localhost:5000/api/student", formData)
          .then((res) => {
            console.log("crete", res.data);
            setSuccessMessage("Data submitted successfully!");
            setTimeout(() => {
              setSuccessMessage("");
            }, 3000);
            setFormData(initialValues);
          })
          .then((error) => {
            console.error("Error:", error);
          });
      }

      setFormSubmitted((prev) => prev + 1);
    } catch (error) {
      console.error("Error:", error);
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <div className="row">
        <label>
          {" "}
          Name:
          <input
            type="text"
            name="name"
            value={formData.name}
            onChange={handleChange}
          />
          <span className="error">{formErrors.name}</span>
        </label>

        <label>
          {" "}
          Address:
          <input
            type="text"
            name="address"
            value={formData.address}
            onChange={handleChange}
          />
          <span className="error">{formErrors.address}</span>
        </label>
      </div>

      <div className="row">
        <label>
          {" "}
          Date of Birth:
          <input
            type="date"
            name="dateOfBirth"
            value={formData.dateOfBirth}
            onChange={handleChange}
          />
          <span className="error">{formErrors.dateOfBirth}</span>
        </label>

        <label>
          {" "}
          Gender:
          <select name="gender" value={formData.gender} onChange={handleChange}>
            <option value="">Select Gender</option>
            <option value="Male">Male</option>
            <option value="Female">Female</option>
          </select>
          <span className="error">{formErrors.gender}</span>
        </label>
      </div>

      <div className="row">
        <label>
          {" "}
          Phone Number:
          <input
            type="number"
            name="phoneNum"
            value={formData.phoneNum}
            onChange={handleChange}
          />
          <span className="error">{formErrors.phoneNum}</span>
        </label>
      </div>

      <button type="submit">{isEdit ? "Update" : "Create"}</button>
      {successMessage && (
        <div className="success-message">{successMessage}</div>
      )}
      {errorsMessage && <div className="error">{errorsMessage}</div>}
    </form>
  );
};

export default MyForm;

Console

Picture 6. When the 'Edit' button is clicked, retrieve the student details by ID(658918e852a0131af4c0aab1), and load the form with the data obtained from the student details.

Code

Picture 7. When the form is submitted, the data entered by the user is sent to the server for processing a return success message and updates the data.

Conclusion

The 'Update' operation plays a fundamental role in ensuring the precision and relevance of data within a React.js application. This step-by-step guide, complemented by real-world examples, empowers developers to effortlessly incorporate edit functionalities into their applications. By gaining a thorough understanding of both 'Create' and 'Update' operations, developers establish a solid foundation for mastering the entire CRUD cycle in React.js applications, all illustrated through practical examples. For your convenience, I have included a zip file containing the source code for the Node.js API and React.js discussed in this article. 

This content is tailored for individuals keen on self-learning. Stay connected with me for further updates and insights.


Orfium Sri Lanka
Globally based Software Developing & Data Processing Company