-
-
Notifications
You must be signed in to change notification settings - Fork 386
Add blocker to prevent changes being lost #197
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: development
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| 'use client'; | ||
| import { startTransition } from 'react'; | ||
| import NextLink from 'next/link'; | ||
| import { useRouter } from 'next/navigation'; | ||
| import { useIsBlocked } from './navigation-block'; | ||
|
|
||
| /** | ||
| * A custom Link component that wraps Next.js's next/link component. | ||
| */ | ||
| export function Link({ | ||
| href, | ||
| children, | ||
| replace, | ||
| ...rest | ||
| }: Parameters<typeof NextLink>[0]) { | ||
| const router = useRouter(); | ||
| const isBlocked = useIsBlocked(); | ||
|
|
||
| return ( | ||
| <NextLink | ||
| href={href} | ||
| onClick={(e) => { | ||
| e.preventDefault(); | ||
|
|
||
| // Cancel navigation | ||
| if (isBlocked && !window.confirm('Do you really want to leave?')) { | ||
| return; | ||
| } | ||
|
|
||
| startTransition(() => { | ||
| const url = href.toString(); | ||
| if (replace) { | ||
| router.replace(url); | ||
| } else { | ||
| router.push(url); | ||
| } | ||
| }); | ||
| }} | ||
| {...rest} | ||
| > | ||
| {children} | ||
| </NextLink> | ||
| ); | ||
| } | ||
|
Comment on lines
+1
to
+44
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Where is this coming from and where is it used? I don't see it imported in your other commits..? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| // components/navigation-block.tsx | ||
| 'use client'; | ||
|
|
||
| import { | ||
| Dispatch, | ||
| SetStateAction, | ||
| createContext, | ||
| useContext, | ||
| useEffect, | ||
| useState, | ||
| } from 'react'; | ||
|
|
||
| const NavigationBlockerContext = createContext< | ||
| [isBlocked: boolean, setBlocked: Dispatch<SetStateAction<boolean>>] | ||
| >([false, () => { }]); | ||
|
|
||
| export function NavigationBlockerProvider({ | ||
| children, | ||
| }: { | ||
| children: React.ReactNode; | ||
| }) { | ||
| // [isBlocked, setBlocked] | ||
| const state = useState(false); | ||
| return ( | ||
| <NavigationBlockerContext.Provider value={state}> | ||
| {children} | ||
| </NavigationBlockerContext.Provider> | ||
| ); | ||
| } | ||
|
|
||
| export function useIsBlocked() { | ||
| const [isBlocked] = useContext(NavigationBlockerContext); | ||
| return isBlocked; | ||
| } | ||
|
|
||
| export function Blocker() { | ||
| const [isBlocked, setBlocked] = useContext(NavigationBlockerContext); | ||
| useEffect(() => { | ||
| setBlocked(() => { | ||
| return true; | ||
| }); | ||
| return () => { | ||
| setBlocked(() => { | ||
| return false; | ||
| }); | ||
| }; | ||
| }, [isBlocked, setBlocked]); | ||
| return null; | ||
| } | ||
|
|
||
| export function BlockBrowserNavigation() { | ||
| const isBlocked = useIsBlocked(); | ||
| useEffect(() => { | ||
| console.log({ isBlocked }); | ||
| if (isBlocked) { | ||
| const showModal = (event: BeforeUnloadEvent) => { | ||
| event.preventDefault(); | ||
| }; | ||
|
|
||
| window.addEventListener('beforeunload', showModal); | ||
| return () => { | ||
| window.removeEventListener('beforeunload', showModal); | ||
| }; | ||
| } | ||
| }, [isBlocked]); | ||
|
|
||
| return null; | ||
| } | ||
|
Comment on lines
+1
to
+68
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Where did you get this solution from? Can you explain me what it does? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. vercel/next.js#41934 (comment) - explains it there |
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can't we leave the ThemeProvider as the top parent? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure I understand the conditional on
<Blocker />. When would<Bocker />be falsy?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When there are no changes to save, we don't need to block navigation away? This is what this is doing.