1
1
export type Callback = ( newSearchParams : string ) => void ;
2
2
3
+ declare global {
4
+ interface Window {
5
+ next ?: {
6
+ router ?: {
7
+ push : ( href : string ) => void ;
8
+ } ;
9
+ } ;
10
+ }
11
+ }
12
+
3
13
export interface UrlStateRouter {
4
14
push ( href : string ) : void ;
5
15
@@ -11,52 +21,58 @@ export type GenericRouterOptions = {
11
21
poolingIntervalMs ?: number ;
12
22
} ;
13
23
14
- const subscribers = new Map < Callback , Callback > ( ) ;
15
-
16
24
let genericRouterCurrentStateString = '' ;
17
25
export class GenericRouter implements UrlStateRouter {
18
26
private interval : number = 0 ;
27
+ private subscribers = new Map < Callback , Callback > ( ) ;
19
28
20
29
constructor ( private options : GenericRouterOptions ) {
21
30
this . options = { poolingIntervalMs : 100 , ...options } ;
22
31
}
23
32
24
33
push ( href : string ) : void {
25
- window . history . pushState ( { } , '' , href ) ;
34
+ // Use Next.js router if available
35
+ // Next.js exposes a global object `window.next.router` with a `push` method for both /pages and /app routes
36
+ if ( typeof window . next ?. router ?. push === 'function' ) {
37
+ window . next . router . push ( href ) ;
38
+ } else {
39
+ window . history . pushState ( { } , '' , href ) ;
40
+ }
26
41
this . onSearchParamsChange ( ) ;
27
42
}
28
43
29
44
subscribe ( fn : Callback ) : void {
30
- subscribers . set ( fn , fn ) ;
45
+ this . subscribers . set ( fn , fn ) ;
31
46
32
47
if ( ! this . interval ) {
33
48
this . startPolling ( ) ;
34
49
}
35
50
}
36
51
37
52
unsubscribe ( fn : Callback ) : void {
38
- subscribers . delete ( fn ) ;
53
+ this . subscribers . delete ( fn ) ;
39
54
40
- if ( subscribers . size === 0 ) {
55
+ if ( this . subscribers . size === 0 ) {
41
56
this . stopPolling ( ) ;
42
57
}
43
58
}
44
59
45
60
onSearchParamsChange ( ) : void {
46
61
if ( window . location . search !== genericRouterCurrentStateString ) {
47
62
genericRouterCurrentStateString = window . location . search ;
48
- subscribers . forEach ( ( subscriber ) =>
63
+ this . subscribers . forEach ( ( subscriber ) =>
49
64
subscriber ( genericRouterCurrentStateString ) ,
50
65
) ;
51
66
}
52
67
}
53
68
54
69
private startPolling ( ) : void {
55
70
// 'popstate' event in browser is not reliable, so we need to poll
71
+ // https://developer.mozilla.org/en-US/docs/Web/API/Window/popstate_event#when_popstate_is_sent
56
72
if ( typeof window !== 'undefined' ) {
57
73
this . interval = setInterval ( ( ) => {
58
74
this . onSearchParamsChange ( ) ;
59
- } , this . options . poolingIntervalMs ) as unknown as number ; // fix for NodeJS
75
+ } , this . options . poolingIntervalMs ) as unknown as number ; // type fix for NodeJS
60
76
}
61
77
}
62
78
0 commit comments