Skip to content

Instantly share code, notes, and snippets.

@julenwang
Created April 11, 2023 10:25
Show Gist options
  • Save julenwang/e3754863c695679a6bea7d454187a628 to your computer and use it in GitHub Desktop.
Save julenwang/e3754863c695679a6bea7d454187a628 to your computer and use it in GitHub Desktop.
useAsyncBlocker for react-router v6.7+
import { useCallback, useRef } from 'react';
import { unstable_useBlocker as useBlocker, useBeforeUnload, useNavigate } from 'react-router-dom';
function useAsyncBlocker(isBlockFn: () => Promise<boolean>) {
const navigate = useNavigate();
const isBlockRef = useRef(true);
const blockerArgsRef = useRef<Parameters<Exclude<Parameters<typeof useBlocker>[0], boolean>>[0]>();
const willBlock = useCallback(async () => {
const isBlock = await isBlockFn();
isBlockRef.current = isBlock;
if (!isBlock) {
const { nextLocation, historyAction } = blockerArgsRef.current!;
if (historyAction === 'POP') {
navigate(-1);
} else {
navigate(nextLocation, { replace: historyAction === 'REPLACE' });
}
}
}, [isBlockFn, navigate]);
useBlocker((args) => {
blockerArgsRef.current = args;
willBlock();
return isBlockRef.current;
});
useBeforeUnload((event) => {
if (isBlockRef.current) {
event.preventDefault();
event.returnValue = '';
}
});
}
export default useAsyncBlocker;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment