1 import type { ReactNode } from 'react';
2 import { createContext, useCallback, useContext, useEffect, useRef, useState } from 'react';
4 import useBeforeUnload from './useBeforeUnload';
6 const PreventLeaveContext = createContext<{
7 clearPendingTasks: () => void;
8 preventLeave: <T>(task: Promise<T>) => Promise<T>;
11 export default function usePreventLeave() {
12 const preventLeaveState = useContext(PreventLeaveContext);
14 if (!preventLeaveState) {
15 throw new Error('PreventLeaveContext is not initialized, wrap the app with PreventLeaveProvider');
18 return preventLeaveState;
21 export const PreventLeaveProvider = ({ children }: { children: ReactNode }) => {
22 const pendingTasks = useRef(new Set<Promise<any>>());
23 const [hasPendingTasks, setHasPendingTasks] = useState(false);
25 const clearPendingTasks = useCallback(() => {
26 pendingTasks.current.clear();
29 const preventLeave = useCallback(
30 <T,>(task: Promise<T>) => {
31 pendingTasks.current.add(task);
33 if (!hasPendingTasks) {
34 setHasPendingTasks(true);
37 const cleanup = () => {
38 pendingTasks.current.delete(task);
40 if (!pendingTasks.current.size) {
41 setHasPendingTasks(false);
45 task.then(cleanup).catch(cleanup);
51 useBeforeUnload(hasPendingTasks);
54 return () => clearPendingTasks();
58 <PreventLeaveContext.Provider value={{ preventLeave, clearPendingTasks }}>
60 </PreventLeaveContext.Provider>