Check your version
This post assumes you're using React Router v6. If not, find your version below.As of today, React Router v6 doesn't ship with support for preventing transitions. Once this issue is resolved, we'll update this post with the recommended way to prevent transitions in your app.
For now, here's a very hacky not "approved" approach that "works".
import * as React from "react";import { UNSAFE_NavigationContext as NavigationContext } from "react-router-dom";export function useBlocker(blocker, when = true) {const { navigator } = React.useContext(NavigationContext);React.useEffect(() => {if (!when) return;const unblock = navigator.block((tx) => {const autoUnblockingTx = {...tx,retry() {unblock();tx.retry();},};blocker(autoUnblockingTx);});return unblock;}, [navigator, blocker, when]);}export default function usePrompt(message, when = true) {const blocker = React.useCallback((tx) => {if (window.confirm(message)) tx.retry();},[message]);useBlocker(blocker, when);}
Now you can usePrompt
in your app. usePrompt
receives two arguments – when
and message
. when
is a boolean that if true
, will show the user a prompt with the message
when they try to navigate away.
function Form() {const [name, setName] = React.useState("");const [email, setEmail] = React.useState("");const [note, setNote] = React.useState("");const isDirty = () => {return name.length > 0 || email.length > 0 || note.length > 0;};usePrompt("Are you sure you want to leave?", isDirty());return (<formonSubmit={(e) => {e.preventDefault();alert("Submitted!");setName("");setEmail("");setNote("");}}>...</form>);}
Here's a Codesandbox with the above implementation.