Last active
February 2, 2024 04:38
-
-
Save buYoung/cd68cc1982888e3fbf27ab6ba6c160ca to your computer and use it in GitHub Desktop.
Custom Hook for React Router v6 Before the Addition of useBlocker
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// use case useStateWithCallbackLazy for blocking Status | |
function Ui(props) { | |
const [promptStatus, setPromptStatus] = useStateWithCallbackLazy(true); | |
const [showPrompt, confirmNavigation, cancelNavigation] = useCallbackPrompt(promptStatus); | |
const handleExit = () => { | |
confirmNavigation(); | |
setPromptStatus(false, () => { | |
navigate(pageUrl }); | |
}); | |
}; | |
return ( | |
<div> | |
<button onClick={handleExit}>exit</button> | |
</div> | |
) | |
} | |
// use case useState for blocking Status | |
function Ui2(props) { | |
const [promptStatus, setPromptStatus] = useState(true); | |
const [showPrompt, confirmNavigation, cancelNavigation] = useCallbackPrompt(promptStatus); | |
const handleExit = () => { | |
confirmNavigation(); | |
setPromptStatus(false); | |
}; | |
useEffect(() => { | |
if (!promptStatus) { | |
showPrompt(); | |
} | |
}, [promptStatus]) | |
return ( | |
<div> | |
<button onClick={handleExit}>exit</button> | |
</div> | |
) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { useEffect, useContext } from 'react'; | |
import { UNSAFE_NavigationContext as NavigationContext } from 'react-router-dom'; | |
import type { History, Blocker, Transition } from 'history'; | |
export interface UseBlockerProps { | |
blocker: Blocker; | |
when?: boolean; | |
} | |
export const useBlocker = ({ blocker, when }: UseBlockerProps): void => { | |
const navigator = useContext(NavigationContext).navigator as History; | |
useEffect(() => { | |
if (!when) return; | |
const unblock = navigator.block((tx: Transition) => { | |
const autoUnblockingTx = { | |
...tx, | |
retry() { | |
unblock(); | |
tx.retry(); | |
}, | |
}; | |
blocker(autoUnblockingTx); | |
}); | |
return unblock; | |
}, [navigator, blocker, when]); | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { useCallback, useState } from 'react'; | |
import { useLocation } from 'react-router-dom'; | |
import type { Transition } from 'history'; | |
import { useBlocker } from 'hooks/useBlocker'; | |
export interface UseCallbackPromptProps { | |
when: boolean; | |
} | |
export interface UseCallbackPrompt { | |
showPrompt: boolean; | |
confirmNavigation: () => void; | |
cancelNavigation: () => void; | |
} | |
export const useCallbackPrompt = ({ when }: UseCallbackPromptProps): UseCallbackPrompt => { | |
const location = useLocation(); | |
const [showPrompt, setShowPrompt] = useState(false); | |
const [blockedLocation, setBlockedLocation] = useState<Transition | null>(null); | |
const cancelNavigation = useCallback(() => { | |
setShowPrompt(false); | |
setBlockedLocation(null); | |
}, []); | |
const blocker = useCallback( | |
(tx: Transition) => { | |
if (tx.location.pathname !== location.pathname) { | |
setBlockedLocation(tx); | |
setShowPrompt(true); | |
} | |
}, | |
[location], | |
); | |
const confirmNavigation = useCallback(() => { | |
if (blockedLocation) { | |
blockedLocation.retry(); | |
cancelNavigation(); | |
} | |
}, [blockedLocation]); | |
useBlocker({ blocker, when }); | |
return { showPrompt, confirmNavigation, cancelNavigation }; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment