Skip to content

Commit a5af53f

Browse files
committed
refactor(history): use an Error object when navigatin to the same place
1 parent 2d0b97d commit a5af53f

File tree

4 files changed

+60
-31
lines changed

4 files changed

+60
-31
lines changed

Diff for: src/history/abstract.js

+13-8
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22

33
import type Router from '../index'
44
import { History } from './base'
5+
import { NavigationDuplicated } from './errors'
56

67
export class AbstractHistory extends History {
7-
index: number;
8-
stack: Array<Route>;
8+
index: number
9+
stack: Array<Route>
910

1011
constructor (router: Router, base: ?string) {
1112
super(router, base)
@@ -34,14 +35,18 @@ export class AbstractHistory extends History {
3435
return
3536
}
3637
const route = this.stack[targetIndex]
37-
this.confirmTransition(route, () => {
38-
this.index = targetIndex
39-
this.updateRoute(route)
40-
}, (err) => {
41-
if (err === 'SAME_ROUTE') {
38+
this.confirmTransition(
39+
route,
40+
() => {
4241
this.index = targetIndex
42+
this.updateRoute(route)
43+
},
44+
err => {
45+
if (err instanceof NavigationDuplicated) {
46+
this.index = targetIndex
47+
}
4348
}
44-
})
49+
)
4550
}
4651

4752
getCurrentLocation () {

Diff for: src/history/base.js

+21-16
Original file line numberDiff line numberDiff line change
@@ -11,24 +11,25 @@ import {
1111
flatMapComponents,
1212
resolveAsyncComponents
1313
} from '../util/resolve-components'
14+
import { NavigationDuplicated } from './errors'
1415

1516
export class History {
16-
router: Router;
17-
base: string;
18-
current: Route;
19-
pending: ?Route;
20-
cb: (r: Route) => void;
21-
ready: boolean;
22-
readyCbs: Array<Function>;
23-
readyErrorCbs: Array<Function>;
24-
errorCbs: Array<Function>;
17+
router: Router
18+
base: string
19+
current: Route
20+
pending: ?Route
21+
cb: (r: Route) => void
22+
ready: boolean
23+
readyCbs: Array<Function>
24+
readyErrorCbs: Array<Function>
25+
errorCbs: Array<Function>
2526

2627
// implemented by sub-classes
27-
+go: (n: number) => void;
28-
+push: (loc: RawLocation) => void;
29-
+replace: (loc: RawLocation) => void;
30-
+ensureURL: (push?: boolean) => void;
31-
+getCurrentLocation: () => string;
28+
+go: (n: number) => void
29+
+push: (loc: RawLocation) => void
30+
+replace: (loc: RawLocation) => void
31+
+ensureURL: (push?: boolean) => void
32+
+getCurrentLocation: () => string
3233

3334
constructor (router: Router, base: ?string) {
3435
this.router = router
@@ -87,7 +88,11 @@ export class History {
8788
confirmTransition (route: Route, onComplete: Function, onAbort?: Function) {
8889
const current = this.current
8990
const abort = err => {
90-
if (isError(err)) {
91+
// after merging https://github.com/vuejs/vue-router/pull/2771 we
92+
// When the user navigates through history through back/forward buttons
93+
// we do not want to throw the error. We only throw it if directly calling
94+
// push/replace. That's why it's not included in isError
95+
if (!(err instanceof NavigationDuplicated) && isError(err)) {
9196
if (this.errorCbs.length) {
9297
this.errorCbs.forEach(cb => { cb(err) })
9398
} else {
@@ -103,7 +108,7 @@ export class History {
103108
route.matched.length === current.matched.length
104109
) {
105110
this.ensureURL()
106-
return abort('SAME_ROUTE')
111+
return abort(new NavigationDuplicated(route))
107112
}
108113

109114
const {

Diff for: src/history/errors.js

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export class NavigationDuplicated extends Error {
2+
constructor () {
3+
super('Navigating to current location is not allowed')
4+
Object.setPrototypeOf(this, new.target.prototype)
5+
}
6+
}

Diff for: test/unit/specs/node.spec.js

+20-7
Original file line numberDiff line numberDiff line change
@@ -27,26 +27,39 @@ describe('Usage in Node', () => {
2727
const router = new VueRouter({
2828
routes: [
2929
{ path: '/', component: Foo },
30-
{ path: '/bar', component: Bar, children: [
31-
{ path: 'baz', component: Baz }
32-
] }
30+
{
31+
path: '/bar',
32+
component: Bar,
33+
children: [{ path: 'baz', component: Baz }]
34+
}
3335
]
3436
})
3537
expect(router.getMatchedComponents('/')).toEqual([Foo])
3638
expect(router.getMatchedComponents('/bar/baz')).toEqual([Bar, Baz])
3739
})
3840

3941
it('should navigate through history with same consecutive routes in history stack', () => {
42+
const success = jasmine.createSpy('complete')
43+
const error = jasmine.createSpy('error')
4044
const router = new VueRouter({
4145
routes: [
4246
{ path: '/', component: { name: 'foo' }},
4347
{ path: '/bar', component: { name: 'bar' }}
4448
]
4549
})
46-
router.push('/')
47-
router.push('/bar')
48-
router.push('/')
49-
router.replace('/bar')
50+
router.push('/', success, error)
51+
expect(success).toHaveBeenCalledTimes(1)
52+
expect(error).toHaveBeenCalledTimes(0)
53+
router.push('/bar', success, error)
54+
expect(success).toHaveBeenCalledTimes(2)
55+
expect(error).toHaveBeenCalledTimes(0)
56+
router.push('/', success, error)
57+
expect(success).toHaveBeenCalledTimes(3)
58+
expect(error).toHaveBeenCalledTimes(0)
59+
router.replace('/bar', success, error)
60+
expect(success).toHaveBeenCalledTimes(4)
61+
expect(error).toHaveBeenCalledTimes(0)
62+
spyOn(console, 'warn')
5063
router.back()
5164
expect(router.history.current.path).toBe('/bar')
5265
router.back()

0 commit comments

Comments
 (0)