1- import { useState } from 'react'
1+ import { useEffect , useState } from 'react'
2+ import { useBlocker } from 'react-router-dom'
23
34let globalIsBlocking = false // If useBlockNavigatingAway gets destroyed, load state from this.
45
@@ -10,17 +11,36 @@ const beforeUnloadHandler = (event: BeforeUnloadEvent) => {
1011
1112export function useBlockNavigatingAway ( ) {
1213 const [ reactiveIsBlocking , setReactiveIsBlocking ] = useState ( globalIsBlocking )
14+ const reactRouterBlocker = useBlocker ( ( ) => reactiveIsBlocking ) // Blocks soft navigation away
15+ // TODO can't have two blockers
16+
17+ function blockNavigatingAway ( ) {
18+ window . addEventListener ( 'beforeunload' , beforeUnloadHandler ) // Blocks hard navigation away
19+ setReactiveIsBlocking ( true )
20+ globalIsBlocking = true
21+ }
22+
23+ function allowNavigatingAway ( ) {
24+ window . removeEventListener ( 'beforeunload' , beforeUnloadHandler )
25+ setReactiveIsBlocking ( false )
26+ globalIsBlocking = false
27+ }
28+
29+ useEffect ( ( ) => {
30+ if ( reactRouterBlocker . state === 'blocked' ) {
31+ if ( window . confirm ( 'You are navigating away. Progress you made may not be saved.' ) ) {
32+ reactRouterBlocker . proceed ( )
33+ allowNavigatingAway ( )
34+ } else {
35+ reactRouterBlocker . reset ( )
36+ }
37+ }
38+ // eslint-disable-next-line react-hooks/exhaustive-deps
39+ } , [ reactRouterBlocker . state ] )
40+
1341 return {
1442 isBlockingNavigatingAway : reactiveIsBlocking ,
15- blockNavigatingAway : ( ) => {
16- window . addEventListener ( 'beforeunload' , beforeUnloadHandler )
17- setReactiveIsBlocking ( true )
18- globalIsBlocking = true
19- } ,
20- allowNavigatingAway : ( ) => {
21- window . removeEventListener ( 'beforeunload' , beforeUnloadHandler )
22- setReactiveIsBlocking ( false )
23- globalIsBlocking = false
24- } ,
43+ blockNavigatingAway,
44+ allowNavigatingAway,
2545 }
2646}
0 commit comments