-
-
Notifications
You must be signed in to change notification settings - Fork 5.3k
/
Copy pathuseWarnWhenUnsavedChanges.tsx
56 lines (47 loc) · 1.75 KB
/
useWarnWhenUnsavedChanges.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
import { useEffect, useRef } from 'react';
import { useFormState, UseFormStateParams } from 'react-final-form';
import { useHistory } from 'react-router-dom';
import { useTranslate } from '../i18n';
/**
* Display a confirmation dialog if the form has unsaved changes.
* - If the user confirms, the navigation continues and the changes are lost.
* - If the user cancels, the navigation is cancelled and the changes are kept.
*/
const useWarnWhenUnsavedChanges = (
enable: boolean,
formRootPathname?: string
) => {
const history = useHistory();
const translate = useTranslate();
const { pristine, submitSucceeded } = useFormState(
UseFormStateSubscription
);
const initialLocation = useRef(
formRootPathname || history.location.pathname
);
useEffect(() => {
if (!enable) {
return;
}
const release = history.block(location => {
const isInsideForm = location.pathname.startsWith(
initialLocation.current
);
if (!pristine && !isInsideForm && !submitSucceeded) {
return translate('ra.message.unsaved_changes');
}
return undefined;
});
return () => {
if (release) {
release();
}
};
}, [pristine, enable, history, translate, submitSucceeded]);
};
const UseFormStateSubscription: UseFormStateParams = {
// For some reason, subscribing only to pristine does not rerender when a field become dirty
// because it has a defaultValue (not initialValue as setting an initialValue does not make the field dirty)
subscription: { pristine: true, dirtyFields: true, submitSucceeded: true },
};
export default useWarnWhenUnsavedChanges;