Skip to content

Instantly share code, notes, and snippets.

@Clarity-89
Created January 13, 2023 07:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Clarity-89/49df2fd5eec7a96d404a88c49440c457 to your computer and use it in GitHub Desktop.
Save Clarity-89/49df2fd5eec7a96d404a88c49440c457 to your computer and use it in GitHub Desktop.
Display Warning for Unsaved Form Data on Page Exit
// FormPrompt.js
import { useEffect } from "react";
export const FormPrompt = ({ hasUnsavedChanges }) => {
useEffect(() => {
const onBeforeUnload = (e) => {
if (hasUnsavedChanges) {
e.preventDefault();
e.returnValue = "";
}
};
window.addEventListener("beforeunload", onBeforeUnload);
return () => {
window.removeEventListener("beforeunload", onBeforeUnload);
};
}, [hasUnsavedChanges]);
};
import { forwardRef } from "react";
import { useForm } from "react-hook-form";
import { useAppState } from "../state";
import { Button, Field, Form, Input, FormPrompt } from "../Forms";
export const Contact = forwardRef((props, ref) => {
const [state, setState] = useAppState();
const {
handleSubmit,
register,
formState: { isDirty },
} = useForm({
defaultValues: state,
mode: "onSubmit",
});
const saveData = (data) => {
setState({ ...state, ...data });
};
return (
<Form onSubmit={handleSubmit(saveData)} nextStep={"/education"}>
<FormPrompt hasUnsavedChanges={isDirty} />
<fieldset>
<legend>Contact</legend>
<Field label="First name">
<Input {...register("firstName")} id="first-name" />
</Field>
<Field label="Last name">
<Input {...register("lastName")} id="last-name" />
</Field>
<Field label="Email">
<Input {...register("email")} type="email" id="email" />
</Field>
<Field label="Password">
<Input {...register("password")} type="password" id="password" />
</Field>
<Button ref={ref}>Next {">"}</Button>
</fieldset>
</Form>
);
});
export const Home = () => {
return <div>Welcome to the home page!</div>;
};
import { useRef } from "react";
import { BrowserRouter as Router, Route, NavLink } from "react-router-dom";
import { AppProvider } from "./state";
import { Contact } from "./Steps/Contact";
import { Education } from "./Steps/Education";
import { About } from "./Steps/About";
import { Confirm } from "./Steps/Confirm";
import "./styles.scss";
import { Stepper } from "./Steps/Stepper";
import { Home } from "./Home";
export const App = () => {
const buttonRef = useRef();
const onStepChange = () => {
buttonRef.current?.click();
};
return (
<div className="App">
<AppProvider>
<Router>
<div className="nav-wrapper">
<NavLink to={"/"}>Home</NavLink>
<Stepper onStepChange={onStepChange} />
</div>
<Route path="/">
<Home />
</Route>
<Route path="/contact">
<Contact ref={buttonRef} />
</Route>
<Route path="/education">
<Education ref={buttonRef} />
</Route>
<Route path="/about">
<About ref={buttonRef} />
</Route>
<Route path="/confirm">
<Confirm />
</Route>
</Router>
</AppProvider>
</div>
);
};
import { useEffect } from "react";
import { Prompt } from "react-router-dom";
const stepLinks = ["/contact", "/education", "/about", "/confirm"];
export const FormPrompt = ({ hasUnsavedChanges }) => {
useEffect(() => {
const onBeforeUnload = (e) => {
if (hasUnsavedChanges) {
e.preventDefault();
e.returnValue = "";
}
};
window.addEventListener("beforeunload", onBeforeUnload);
return () => {
window.removeEventListener("beforeunload", onBeforeUnload);
};
}, [hasUnsavedChanges]);
const onLocationChange = (location) => {
if (stepLinks.includes(location.pathname)) {
return true;
}
return "You have unsaved changes, are you sure you want to leave?";
};
return <Prompt when={hasUnsavedChanges} message={onLocationChange} />;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment