Skip to content

Commit b865b42

Browse files
authored
fix(router-core): onStay callback should use 'current' matches not 'previous' (#5485)
1 parent 0761f79 commit b865b42

File tree

2 files changed

+108
-2
lines changed

2 files changed

+108
-2
lines changed

packages/router-core/src/router.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2111,8 +2111,8 @@ export class RouterCore<
21112111
(match) =>
21122112
!previousMatches.some((d) => d.id === match.id),
21132113
)
2114-
stayingMatches = previousMatches.filter((match) =>
2115-
newMatches.some((d) => d.id === match.id),
2114+
stayingMatches = newMatches.filter((match) =>
2115+
previousMatches.some((d) => d.id === match.id),
21162116
)
21172117

21182118
return {
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import { describe, expect, it, vi } from 'vitest'
2+
import { createMemoryHistory } from '@tanstack/history'
3+
import { BaseRootRoute, BaseRoute, RouterCore } from '../src'
4+
5+
describe('callbacks', () => {
6+
const setup = ({
7+
onEnter,
8+
onLeave,
9+
onStay,
10+
}: {
11+
onEnter?: () => void
12+
onLeave?: () => void
13+
onStay?: () => void
14+
}) => {
15+
const rootRoute = new BaseRootRoute({})
16+
17+
const fooRoute = new BaseRoute({
18+
getParentRoute: () => rootRoute,
19+
path: '/foo',
20+
onLeave,
21+
onEnter,
22+
onStay,
23+
})
24+
25+
const barRoute = new BaseRoute({
26+
getParentRoute: () => rootRoute,
27+
path: '/bar',
28+
onLeave,
29+
onEnter,
30+
onStay,
31+
})
32+
33+
const routeTree = rootRoute.addChildren([fooRoute, barRoute])
34+
35+
const router = new RouterCore({
36+
routeTree,
37+
history: createMemoryHistory(),
38+
})
39+
40+
return router
41+
}
42+
describe('onEnter', () => {
43+
it('runs on navigate to a new route', async () => {
44+
const onEnter = vi.fn()
45+
const router = setup({ onEnter })
46+
47+
// Entering foo
48+
await router.navigate({ to: '/foo' })
49+
expect(onEnter).toHaveBeenNthCalledWith(
50+
1,
51+
expect.objectContaining({ id: '/foo' }),
52+
)
53+
54+
// Entering bar
55+
await router.navigate({ to: '/bar' })
56+
expect(onEnter).toHaveBeenNthCalledWith(
57+
2,
58+
expect.objectContaining({ id: '/bar' }),
59+
)
60+
})
61+
})
62+
63+
describe('onLeave', () => {
64+
it('runs on navigate from a previous route', async () => {
65+
const onLeave = vi.fn()
66+
const router = setup({ onLeave })
67+
await router.navigate({ to: '/foo' })
68+
69+
// Leaving foo to bar
70+
await router.navigate({ to: '/bar' })
71+
expect(onLeave).toHaveBeenNthCalledWith(
72+
1,
73+
expect.objectContaining({ id: '/foo' }),
74+
)
75+
76+
// Leaving bar to foo
77+
await router.navigate({ to: '/foo' })
78+
expect(onLeave).toHaveBeenNthCalledWith(
79+
2,
80+
expect.objectContaining({ id: '/bar' }),
81+
)
82+
})
83+
})
84+
85+
describe('onStay', () => {
86+
it('runs on navigate to the same route', async () => {
87+
const onStay = vi.fn()
88+
const router = setup({ onStay })
89+
await router.navigate({ to: '/foo' })
90+
91+
// Staying on foo
92+
await router.navigate({ to: '/foo', search: { foo: 'baz' } })
93+
expect(onStay).toHaveBeenNthCalledWith(
94+
1,
95+
expect.objectContaining({ id: '/foo', search: { foo: 'baz' } }),
96+
)
97+
98+
// Staying on foo
99+
await router.navigate({ to: '/foo', search: { foo: 'quux' } })
100+
expect(onStay).toHaveBeenNthCalledWith(
101+
2,
102+
expect.objectContaining({ id: '/foo', search: { foo: 'quux' } }),
103+
)
104+
})
105+
})
106+
})

0 commit comments

Comments
 (0)