javascript 37 lines · 7 steps

Guarding unsaved changes with a React hook

A custom hook that warns users before they lose unsaved work, covering both browser navigation and in-app route changes.

Explained by highlit
1import { useEffect, useRef } from "react";
2import { useBlocker } from "react-router-dom";
3 
4export function useUnsavedChangesPrompt(isDirty, message = "You have unsaved changes. Leave anyway?") {
5 const messageRef = useRef(message);
6 messageRef.current = message;
7 
8 useEffect(() => {
9 if (!isDirty) return;
10 
11 const handleBeforeUnload = (event) => {
12 event.preventDefault();
13 event.returnValue = messageRef.current;
14 return messageRef.current;
15 };
16 
17 window.addEventListener("beforeunload", handleBeforeUnload);
18 return () => window.removeEventListener("beforeunload", handleBeforeUnload);
19 }, [isDirty]);
20 
21 const blocker = useBlocker(
22 ({ currentLocation, nextLocation }) =>
23 isDirty && currentLocation.pathname !== nextLocation.pathname
24 );
25 
26 useEffect(() => {
27 if (blocker.state !== "blocked") return;
28 
29 if (window.confirm(messageRef.current)) {
30 blocker.proceed();
31 } else {
32 blocker.reset();
33 }
34 }, [blocker]);
35 
36 return blocker;
37}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1A ref lets an effect read the latest prop value without re-subscribing every time it changes.
  2. 2Guarding unsaved work needs two mechanisms: the native beforeunload event for full page exits and a router blocker for SPA navigation.
  3. 3Always pair addEventListener with a cleanup function so effects don't leak stale handlers.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Guarding unsaved changes with a React hook — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code