@@ -3,7 +3,7 @@ import { EventEmitter } from 'events'
33import evalScript from '../eval-script'
44import shallowEquals from '../shallow-equals'
55import PQueue from '../p-queue'
6- import { loadGetInitialProps , getLocationOrigin } from '../utils'
6+ import { loadGetInitialProps , getURL } from '../utils'
77import { _notifyBuildIdMismatch } from './'
88import fetch from 'unfetch'
99
@@ -26,7 +26,7 @@ if (typeof window !== 'undefined' && typeof navigator.serviceWorker !== 'undefin
2626}
2727
2828export default class Router extends EventEmitter {
29- constructor ( pathname , query , { Component, ErrorComponent, err } = { } ) {
29+ constructor ( pathname , query , as , { Component, ErrorComponent, err } = { } ) {
3030 super ( )
3131 // represents the current component key
3232 this . route = toRoute ( pathname )
@@ -41,6 +41,7 @@ export default class Router extends EventEmitter {
4141 this . ErrorComponent = ErrorComponent
4242 this . pathname = pathname
4343 this . query = query
44+ this . as = as
4445 this . subscriptions = new Set ( )
4546 this . componentLoadCancel = null
4647 this . onPopState = this . onPopState . bind ( this )
@@ -66,42 +67,12 @@ export default class Router extends EventEmitter {
6667 // Actually, for (1) we don't need to nothing. But it's hard to detect that event.
6768 // So, doing the following for (1) does no harm.
6869 const { pathname, query } = this
69- this . replace ( format ( { pathname, query } ) , getURL ( ) )
70+ this . changeState ( 'replaceState' , format ( { pathname, query } ) , getURL ( ) )
7071 return
7172 }
7273
7374 const { url, as } = e . state
74- const { pathname, query } = parse ( url , true )
75-
76- this . abortComponentLoad ( as )
77-
78- if ( ! this . urlIsNew ( pathname , query ) ) {
79- this . emit ( 'routeChangeStart' , as )
80- this . emit ( 'routeChangeComplete' , as )
81- return
82- }
83-
84- const route = toRoute ( pathname )
85-
86- this . emit ( 'routeChangeStart' , as )
87- const {
88- data,
89- props,
90- error
91- } = await this . getRouteInfo ( route , pathname , query , as )
92-
93- if ( error && error . cancelled ) {
94- return
95- }
96-
97- this . route = route
98- this . set ( pathname , query , { ...data , props } )
99-
100- if ( error ) {
101- this . emit ( 'routeChangeError' , error , as )
102- } else {
103- this . emit ( 'routeChangeComplete' , as )
104- }
75+ this . replace ( url , as )
10576 }
10677
10778 update ( route , Component ) {
@@ -160,6 +131,13 @@ export default class Router extends EventEmitter {
160131 this . abortComponentLoad ( as )
161132 const { pathname, query } = parse ( url , true )
162133
134+ // If the url change is only related to a hash change
135+ // We should not proceed. We should only replace the state.
136+ if ( this . onlyAHashChange ( as ) ) {
137+ this . changeState ( 'replaceState' , url , as )
138+ return
139+ }
140+
163141 // If asked to change the current URL we should reload the current page
164142 // (not location.reload() but reload getInitalProps and other Next.js stuffs)
165143 // We also need to set the method = replaceState always
@@ -180,9 +158,10 @@ export default class Router extends EventEmitter {
180158 }
181159
182160 this . changeState ( method , url , as )
161+ const hash = window . location . hash . substring ( 1 )
183162
184163 this . route = route
185- this . set ( pathname , query , { ...data , props } )
164+ this . set ( pathname , query , as , { ...data , props, hash } )
186165
187166 if ( error ) {
188167 this . emit ( 'routeChangeError' , error , as )
@@ -228,12 +207,33 @@ export default class Router extends EventEmitter {
228207 return routeInfo
229208 }
230209
231- set ( pathname , query , data ) {
210+ set ( pathname , query , as , data ) {
232211 this . pathname = pathname
233212 this . query = query
213+ this . as = as
234214 this . notify ( data )
235215 }
236216
217+ onlyAHashChange ( as ) {
218+ if ( ! this . as ) return false
219+ const [ oldUrlNoHash ] = this . as . split ( '#' )
220+ const [ newUrlNoHash , newHash ] = as . split ( '#' )
221+
222+ // If the urls are change, there's more than a hash change
223+ if ( oldUrlNoHash !== newUrlNoHash ) {
224+ return false
225+ }
226+
227+ // If there's no hash in the new url, we can't consider it as a hash change
228+ if ( ! newHash ) {
229+ return false
230+ }
231+
232+ // Now there's a hash in the new URL.
233+ // We don't need to worry about the old hash.
234+ return true
235+ }
236+
237237 urlIsNew ( pathname , query ) {
238238 return this . pathname !== pathname || ! shallowEquals ( query , this . query )
239239 }
@@ -346,12 +346,6 @@ export default class Router extends EventEmitter {
346346 }
347347}
348348
349- function getURL ( ) {
350- const { href } = window . location
351- const origin = getLocationOrigin ( )
352- return href . substring ( origin . length )
353- }
354-
355349function toRoute ( path ) {
356350 return path . replace ( / \/ $ / , '' ) || '/'
357351}
0 commit comments