I am building SPA application. I have component with form changes to which could be either saved or canceled depending which button user pressed. I have a flag which indicates that some changes were made in this form.
I am using react-router-dom
v6 for routing like this:
<Routes>
<Route />
<Route />
<Route />
</Routes>
I want to show user a warning when he has unsaved changes and trying to navigate to another page (another route). It seems to me that there is no such a mechanic, I am also still not able to write a pure js script to solve this problem. beforeunload
not working for me because it is only triggered on page refresh.
Is there any way I can achieve this?
This component accompanied by usage of the new createBrowserRouter react-router-dom
api solved my problem.
Anthough it is still not clear how to appropriately use it with query params, blocker seems not be working when I am changing them.
import { useDidUpdate, useDisclosure } from '@mantine/hooks';
import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { unstable_BlockerFunction, useBlocker } from 'react-router-dom';
import { WarningModal } from '../Modals/WarningModal/WarningModal';
interface Props {
shouldBlock: boolean | unstable_BlockerFunction;
}
const ChangesUnsavedBlocker = memo((props: Props) => {
const { shouldBlock } = props;
const { t } = useTranslation('common', {
keyPrefix: 'changes_unsaved_blocker',
});
// https://reactrouter.com/en/6.21.1/hooks/use-blocker
const blocker = useBlocker(shouldBlock);
const [warningShown, { open: showWarning, close: hideWarning }] = useDisclosure(false);
useDidUpdate(() => {
if (blocker.state === 'blocked') {
showWarning();
} else {
hideWarning();
}
}, [blocker.state]);
const handleProceed = useCallback(() => {
blocker.proceed?.();
hideWarning();
}, [blocker, hideWarning]);
const handleReset = useCallback(() => {
blocker.reset?.();
hideWarning();
}, [blocker, hideWarning]);
return (
<WarningModal
width="416px"
icon="warning"
maxHeight="348px"
title={t('title')}
annotation={t('annotation')}
approveTitle={t<string>('approve_title')}
isOpened={warningShown}
onClose={handleReset}
onCancel={handleReset}
onApprove={handleProceed}
/>
);
});
export { ChangesUnsavedBlocker };