# Unsaved Changes Warning in React

In this tutorial, we'll explore how to implement an unsaved change warning in a React application. Instead of relying on third-party libraries, we'll build a custom hook that's both lightweight and tailored to our needs.

## Getting Started

You can either clone the project from [GitHub](https://github.com/MHNahib/react-load-or-close-warning/tree/preset) to use the base template or follow along with your existing setup.

For this project, we've used [Vite](https://vitejs.dev/) for efficiency and [Tailwind](https://tailwindcss.com/) for styling.

## Building the Comment Form

Let's start by creating a basic form named `CommentForm` with two states: `name` and `comment`. Upon clicking the button, it will display a success or failure message based on whether the form is filled.

```typescript
import { useState } from "react";
import { useUnsavedChangeWarning } from "../hooks/useUnsavedChangeWarning";

const CommentForm = () => {
  const [name, setName] = useState<string>("");
  const [comment, setComment] = useState<string>("");

  useUnsavedChangeWarning(!name || !comment);

  return (
    <div className="flex justify-center items-center h-[100vh]">
      <div className="md:w-[600px] max-w-md p-6 bg-white border border-gray-200 rounded-lg shadow">
        <h5 className="mb-2 text-2xl font-semibold tracking-tight text-gray-900 ">
          Comment Now
        </h5>
        <div className="flex flex-col">
          <label htmlFor="name" className="my-2">
            Your name
          </label>
          <input
            id="name"
            name="name"
            placeholder="Your Name"
            className="shadow-sm bg-gray-50 border border-gray-30 p-2.5"
            value={name}
            onChange={(e) => setName(e.target.value)}
            autoComplete="off"
          />
        </div>
        <div className="flex flex-col">
          <label htmlFor="comment" className="my-2">
            Your Comment
          </label>
          <textarea
            id="comment"
            name="comment"
            value={comment}
            onChange={(e) => setComment(e.target.value)}
            placeholder="Your Comment"
            className="shadow-sm bg-gray-50 border border-gray-30 p-2.5 w-full"
          ></textarea>
        </div>
        <button
          className="bg-blue-500 hover:bg-blue-700 px-2 py-3 mt-4 shadow rounded-lg text-white"
          onClick={() => {
            if (name && comment) alert("Successful!");
            else alert("Failed!");
          }}
        >
          Comment Now
        </button>
      </div>
    </div>
  );
};

export default CommentForm;
```

Next, import `CommentForm` into your `App.tsx`:

```typescript
// App.tsx
import CommentForm from "./components/CommentForm";

export default function App() {
  return <CommentForm />;
}
```

The Image below refers to the design of the page.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1700067747948/0493d4b2-7a70-4116-b542-d4fa8194fbba.png align="center")

## Creating the Unsaved Changes Warning Hook

Now, let's build a custom hook named `useUnsavedChangeWarning`. Inside the `hooks` folder, create a new file named `useUnsavedChangeWarning.tsx`:

```jsx
// useUnsavedChangeWarning.tsx

import { useEffect } from "react";

const handleUnsavedEvent = (e: BeforeUnloadEvent, condition: boolean) => {
  if (condition) {
    e.preventDefault();
    e.returnValue = true;
  }
};

export const useUnsavedChangeWarning = (isUnsaved: boolean) => {
  useEffect(() => {
    window.addEventListener("beforeunload", (e) =>
      handleUnsavedEvent(e, isUnsaved)
    );
    return () =>
      window.removeEventListener("beforeunload", (e) =>
        handleUnsavedEvent(e, isUnsaved)
      );
  }, [isUnsaved]);
};
```

This hook takes a boolean parameter `isUnsaved` to determine whether there are unsaved changes. It adds an event listener for the [`beforeunload`](https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event) event, triggering the `handleUnsavedEvent` function. The cleanup function removes the event listener on component unmount or when `isUnsaved` changes.

## Integrating the Hook

Import and use the `useUnsavedChangeWarning` hook in `CommentForm`:

```typescript
// CommentForm.tsx
import React, { useState } from "react";
import useUnsavedChangeWarning from "../hooks/useUnsavedChangeWarning";

const CommentForm = () => {
  const [name, setName] = useState("");
  const [comment, setComment] = useState("");

  useUnsavedChangeWarning(!name || !comment);

  // Rest of the form code...
};

export default CommentForm;
```

With this implementation, your React application will now display a warning when users attempt to close the window without saving changes. This custom hook approach keeps your codebase clean and free from unnecessary dependencies.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1700068116303/58cadf18-4410-4319-a998-d7eefbd7021b.gif align="center")

Feel free to customize it further to suit your specific requirements.

Remember to share your thoughts or improvements in the comments below! Happy coding!
