-
-
Notifications
You must be signed in to change notification settings - Fork 10.7k
Closed as not planned
Closed as not planned
Copy link
Labels
Description
What version of React Router are you using?
6.25.1
Steps to Reproduce
- create a Navigation Blocker Hook (which blocks query params change as well)
import { useEffect, useCallback } from 'react';
import { useLocation, useBeforeUnload, useBlocker } from 'react-router-dom';
import { validate as validateUUID } from 'uuid';
const useNavigationBlocker = (
shouldBlock: boolean,
checkSearchParams?: boolean,
) => {
const location = useLocation();
const blocker = useBlocker(
useCallback(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(tx: any) => {
if (!shouldBlock) return false;
const nextLocation = tx.nextLocation;
const currentPathname = location.pathname;
const nextPathname = nextLocation.pathname;
const currPathNameArr = currentPathname
.split('/')
.filter(Boolean);
const nextPathNameArr = nextPathname.split('/').filter(Boolean);
// Check for search params changes
if (checkSearchParams) {
const currentSearchParams = new URLSearchParams(
location.search,
);
const nextSearchParams = new URLSearchParams(
nextLocation.search,
);
const searchParamsChanged =
Array.from(currentSearchParams.entries()).some(
([key, value]) =>
nextSearchParams.get(key) !== value,
) ||
Array.from(nextSearchParams.entries()).some(
([key, value]) =>
currentSearchParams.get(key) !== value,
);
if (searchParamsChanged) {
return true; // Block navigation if search params have changed
}
}
// Allow navigation if saving a new item and redirecting to the item details page
if (
currPathNameArr.length === 2 &&
nextPathNameArr.length === 2 &&
currPathNameArr[0] === nextPathNameArr[0] &&
currPathNameArr[1] === 'new' &&
validateUUID(nextPathNameArr[1])
) {
return false;
}
// Allow navigation if only search params are different
if (currentPathname === nextPathname) {
return false;
}
return true;
},
[shouldBlock, location, checkSearchParams],
),
);
useBeforeUnload(
useCallback(
(event) => {
if (shouldBlock) {
event.preventDefault();
event.returnValue = '';
}
},
[shouldBlock],
),
);
useEffect(() => {
if (blocker.state === 'blocked') {
const proceed = window.confirm(
'You have unsaved changes. Are you sure you want to leave?',
);
if (proceed) {
setTimeout(blocker.proceed, 0);
} else {
blocker.reset();
}
}
}, [blocker]);
return blocker.state === 'blocked';
};
export default useNavigationBlocker;
- use this Hook in your Component
- fetch value of query using useSearchParam
- update the query params on some button click
- cancel the navigation change confirmation
- you will get the new value from the query param
Expected Behavior
after cancelling the navigation prompt you are blocking the navigation, though it doesn't reflect on the query in url, it updates in the state (searchParam)
Actual Behavior
it should be returning the old value in searchParam, after navigation is blocked
Styn and ronaldcurtis