useConfirmOnClose.tsx67 lines · main
1import { useCallback, useMemo, useState } from 'react'
2
3import useLatest from '../misc/useLatest'
4
5export interface ConfirmOnCloseModalProps {
6 visible: boolean
7 onClose: () => void
8 onCancel: () => void
9}
10
11interface UseConfirmOnCloseProps {
12 checkIsDirty: () => boolean
13 onClose: () => void
14}
15
16export const useConfirmOnClose = ({ checkIsDirty, onClose }: UseConfirmOnCloseProps) => {
17 const [visible, setVisible] = useState(false)
18
19 const checkIsDirtyRef = useLatest(checkIsDirty)
20 const onCloseRef = useLatest(onClose)
21
22 const confirmOnClose = useCallback(() => {
23 if (checkIsDirtyRef.current()) {
24 setVisible(true)
25 } else {
26 onCloseRef.current()
27 }
28 // eslint-disable-next-line react-hooks/exhaustive-deps
29 }, [])
30
31 const handleOpenChange = useCallback(
32 (open: boolean) => {
33 if (!open) {
34 confirmOnClose()
35 }
36 },
37 [confirmOnClose]
38 )
39
40 const onConfirm = useCallback(() => {
41 setVisible(false)
42 onCloseRef.current()
43 // eslint-disable-next-line react-hooks/exhaustive-deps
44 }, [])
45
46 const onCancel = useCallback(() => {
47 setVisible(false)
48 }, [])
49
50 const modalProps: ConfirmOnCloseModalProps = useMemo(
51 () => ({
52 visible,
53 onClose: onConfirm,
54 onCancel,
55 }),
56 [visible, onConfirm, onCancel]
57 )
58
59 return useMemo(
60 () => ({
61 confirmOnClose,
62 handleOpenChange,
63 modalProps,
64 }),
65 [confirmOnClose, handleOpenChange, modalProps]
66 )
67}