Allow the application to block navigations within the SPA and present the user a confirmation dialog to confirm the navigation. Mostly used to avoid using half-filled form data. This does not handle hard-reloads or cross-origin navigations.
The Blocker
object returned by the hook has the following properties:
state
unblocked
- the blocker is idle and has not prevented any navigationblocked
- the blocker has prevented a navigationproceeding
- the blocker is proceeding through from a blocked navigationlocation
blocked
state, this represents the Location
to which
we blocked a navigation. When in a proceeding
state, this is the
location being navigated to after a blocker.proceed()
call.proceed()
blocked
state, you may call blocker.proceed()
to proceed to
the blocked location.reset()
blocked
state, you may call blocker.reset()
to return the
blocker to an unblocked
state and leave the user at the current
location.// Boolean version
let blocker = useBlocker(value !== "");
// Function version
let blocker = useBlocker(
({ currentLocation, nextLocation, historyAction }) =>
value !== "" &&
currentLocation.pathname !== nextLocation.pathname
);
function useBlocker(shouldBlock: boolean | BlockerFunction): Blocker
Either a boolean or a function returning a boolean which indicates whether the navigation should be blocked. The function format
receives a single object parameter containing the currentLocation
,
nextLocation
, and historyAction
of the potential navigation.
A Blocker
object with state and reset functionality
import { useCallback, useState } from "react";
import { BlockerFunction, useBlocker } from "react-router";
export function ImportantForm() {
const [value, setValue] = useState("");
const shouldBlock = useCallback<BlockerFunction>(
() => value !== "",
[value]
);
const blocker = useBlocker(shouldBlock);
return (
<form
onSubmit={(e) => {
e.preventDefault();
setValue("");
if (blocker.state === "blocked") {
blocker.proceed();
}
}}
>
<input
name="data"
value={value}
onChange={(e) => setValue(e.target.value)}
/>
<button type="submit">Save</button>
{blocker.state === "blocked" ? (
<>
<p style={{ color: "red" }}>
Blocked the last navigation to
</p>
<button
type="button"
onClick={() => blocker.proceed()}
>
Let me through
</button>
<button
type="button"
onClick={() => blocker.reset()}
>
Keep me here
</button>
</>
) : blocker.state === "proceeding" ? (
<p style={{ color: "orange" }}>
Proceeding through blocked navigation
</p>
) : (
<p style={{ color: "green" }}>
Blocker is currently unblocked
</p>
)}
</form>
);
}