Skip to content

Commit a7052b6

Browse files
authored
feat(vue-app): trigger watchParam when param is changed in same route (nuxt#6244)
1 parent 52caef2 commit a7052b6

File tree

5 files changed

+151
-77
lines changed

5 files changed

+151
-77
lines changed

packages/vue-app/template/client.js

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -137,20 +137,21 @@ function mapTransitions (toComponents, to, from) {
137137
}
138138
<% } %>
139139
<% if (loading) { %>async <% } %>function loadAsyncComponents (to, from, next) {
140-
// Check if route path changed (this._pathChanged), only if the page is not an error (for validate())
141-
this._pathChanged = Boolean(app.nuxt.err) || from.path !== to.path
142-
this._queryChanged = JSON.stringify(to.query) !== JSON.stringify(from.query)
140+
// Check if route changed (this._routeChanged), only if the page is not an error (for validate())
141+
this._routeChanged = Boolean(app.nuxt.err) || from.name !== to.name
142+
this._paramChanged = !this._routeChanged && from.path !== to.path
143+
this._queryChanged = !this._paramChanged && from.fullPath !== to.fullPath
143144
this._diffQuery = (this._queryChanged ? getQueryDiff(to.query, from.query) : [])
144145

145146
<% if (loading) { %>
146-
if (this._pathChanged && this.$loading.start && !this.$loading.manual) {
147+
if ((this._routeChanged || this._paramChanged) && this.$loading.start && !this.$loading.manual) {
147148
this.$loading.start()
148149
}
149150
<% } %>
150151

151152
try {
152153
<% if (loading) { %>
153-
if (!this._pathChanged && this._queryChanged) {
154+
if (this._queryChanged) {
154155
const Components = await resolveRouteComponents(
155156
to,
156157
(Component, instance) => ({ Component, instance })
@@ -268,7 +269,7 @@ function callMiddleware () {
268269
}
269270
<% } %>
270271
async function render (to, from, next) {
271-
if (this._pathChanged === false && this._queryChanged === false) {
272+
if (this._routeChanged === false && this._paramChanged === false && this._queryChanged === false) {
272273
return next()
273274
}
274275
// Handle first render on SPA mode
@@ -432,11 +433,17 @@ async function render (to, from, next) {
432433
// Check if only children route changed
433434
Component._path = compile(to.matched[matches[i]].path)(to.params)
434435
Component._dataRefresh = false
435-
// Check if Component need to be refreshed (call asyncData & fetch)
436-
// Only if its slug has changed or is watch query changes
437-
if ((this._pathChanged && this._queryChanged) || Component._path !== _lastPaths[i]) {
436+
const childPathChanged = Component._path !== _lastPaths[i]
437+
// Refresh component (call asyncData & fetch) when:
438+
// Route path changed part includes current component
439+
// Or route param changed part includes current component and watchParam is not `false`
440+
// Or route query is changed and watchQuery returns `true`
441+
if (this._routeChanged && childPathChanged) {
438442
Component._dataRefresh = true
439-
} else if (!this._pathChanged && this._queryChanged) {
443+
} else if (this._paramChanged && childPathChanged) {
444+
const watchParam = Component.options.watchParam
445+
Component._dataRefresh = watchParam !== false
446+
} else if (this._queryChanged) {
440447
const watchQuery = Component.options.watchQuery
441448
if (watchQuery === true) {
442449
Component._dataRefresh = true
@@ -584,7 +591,7 @@ function showNextPage (to) {
584591
// When navigating on a different route but the same component is used, Vue.js
585592
// Will not update the instance data, so we have to update $data ourselves
586593
function fixPrepatch (to, ___) {
587-
if (this._pathChanged === false && this._queryChanged === false) {
594+
if (this._routeChanged === false && this._paramChanged === false && this._queryChanged === false) {
588595
return
589596
}
590597

test/dev/unicode-base.size-limit.test.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ describe('nuxt minimal vue-app bundle size limit', () => {
2020
it('should stay within the size limit range', async () => {
2121
const filter = filename => filename === 'vue-app.nuxt.js'
2222
const legacyResourcesSize = await getResourcesSize(distDir, 'client', { filter })
23-
2423
const LEGACY_JS_RESOURCES_KB_SIZE = 15.7
2524
expect(legacyResourcesSize.uncompressed).toBeWithinSize(LEGACY_JS_RESOURCES_KB_SIZE)
2625
})

test/e2e/children.patch.browser.test.js

Lines changed: 98 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ describe('children patch (browser)', () => {
2727
})
2828
})
2929

30-
test('Loading /patch and keep ', async () => {
30+
test('Loading /patch and keep', async () => {
3131
page = await browser.page(url('/patch'))
3232

3333
const h1 = await page.$text('h1')
@@ -37,86 +37,119 @@ describe('children patch (browser)', () => {
3737
dates.patch = await page.$text('[data-date-patch]')
3838
})
3939

40-
test('Navigate to /patch/1', async () => {
41-
const { hook } = await page.nuxt.navigate('/patch/1', false)
42-
await hook
40+
describe('refresh child component if param changed', () => {
41+
test('Navigate to /patch/1', async () => {
42+
const { hook } = await page.nuxt.navigate('/patch/1', false)
43+
await hook
4344

44-
const h2 = await page.$text('h2')
45-
expect(h2.includes('_id:')).toBe(true)
46-
dates.id = await page.$text('[data-date-id]')
45+
const h2 = await page.$text('h2')
46+
expect(h2.includes('_id:')).toBe(true)
47+
dates.id = await page.$text('[data-date-id]')
4748

48-
expect(dates.patch).toBe(await page.$text('[data-date-patch]'))
49-
})
49+
expect(dates.patch).toBe(await page.$text('[data-date-patch]'))
50+
})
5051

51-
test('Navigate to /patch/2', async () => {
52-
await page.nuxt.navigate('/patch/2')
53-
const date = await page.$text('[data-date-id]')
52+
test('Navigate to /patch/2', async () => {
53+
await page.nuxt.navigate('/patch/2')
54+
const date = await page.$text('[data-date-id]')
5455

55-
expect(await page.$text('h3')).toBe('Index')
56-
expect(dates.patch).toBe(await page.$text('[data-date-patch]'))
57-
expect(+dates.id < +date).toBe(true)
58-
dates.id = date
56+
expect(await page.$text('h3')).toBe('Index')
57+
expect(dates.patch).toBe(await page.$text('[data-date-patch]'))
58+
expect(+dates.id < +date).toBe(true)
59+
dates.id = date
60+
})
5961
})
6062

61-
test('Navigate to /patch/2?test=true', async () => {
62-
await page.nuxt.navigate('/patch/2?test=true')
63-
expect(dates.patch).toBe(await page.$text('[data-date-patch]'))
64-
expect(dates.id).toBe(await page.$text('[data-date-id]'))
65-
})
63+
describe('resue component if only query is changed', () => {
64+
test('Navigate to /patch/2?test=true', async () => {
65+
await page.nuxt.navigate('/patch/2?test=true')
66+
expect(dates.patch).toBe(await page.$text('[data-date-patch]'))
67+
expect(dates.id).toBe(await page.$text('[data-date-id]'))
68+
})
6669

67-
test('Navigate to /patch/2#test', async () => {
68-
await page.nuxt.navigate('/patch/2#test')
69-
expect(dates.patch).toBe(await page.$text('[data-date-patch]'))
70-
expect(dates.id).toBe(await page.$text('[data-date-id]'))
70+
test('Navigate to /patch/2#test', async () => {
71+
await page.nuxt.navigate('/patch/2#test')
72+
expect(dates.patch).toBe(await page.$text('[data-date-patch]'))
73+
expect(dates.id).toBe(await page.$text('[data-date-id]'))
74+
})
7175
})
7276

73-
test('Navigate to /patch/2/child', async () => {
74-
await page.nuxt.navigate('/patch/2/child')
75-
dates.child = await page.$text('[data-date-child]')
76-
dates.slug = await page.$text('[data-date-child-slug]')
77+
describe('refresh child component if param is changed', () => {
78+
test('Navigate to /patch/2/child', async () => {
79+
await page.nuxt.navigate('/patch/2/child')
80+
dates.child = await page.$text('[data-date-child]')
81+
dates.slug = await page.$text('[data-date-child-slug]')
7782

78-
expect(dates.patch).toBe(await page.$text('[data-date-patch]'))
79-
expect(dates.id).toBe(await page.$text('[data-date-id]'))
80-
expect(+dates.child > +dates.id).toBe(true)
81-
expect(+dates.slug > +dates.child).toBe(true)
82-
})
83+
expect(dates.patch).toBe(await page.$text('[data-date-patch]'))
84+
expect(dates.id).toBe(await page.$text('[data-date-id]'))
85+
expect(+dates.child > +dates.id).toBe(true)
86+
expect(+dates.slug > +dates.child).toBe(true)
87+
})
8388

84-
test('Navigate to /patch/2/child/1', async () => {
85-
await page.nuxt.navigate('/patch/2/child/1')
86-
const date = await page.$text('[data-date-child-slug]')
89+
test('Navigate to /patch/2/child/1', async () => {
90+
await page.nuxt.navigate('/patch/2/child/1')
91+
const date = await page.$text('[data-date-child-slug]')
8792

88-
expect(dates.patch).toBe(await page.$text('[data-date-patch]'))
89-
expect(dates.id).toBe(await page.$text('[data-date-id]'))
90-
expect(dates.child).toBe(await page.$text('[data-date-child]'))
91-
expect(+date > +dates.slug).toBe(true)
92-
dates.slug = date
93-
})
93+
expect(dates.patch).toBe(await page.$text('[data-date-patch]'))
94+
expect(dates.id).toBe(await page.$text('[data-date-id]'))
95+
expect(dates.child).toBe(await page.$text('[data-date-child]'))
96+
expect(+date > +dates.slug).toBe(true)
97+
dates.slug = date
98+
})
9499

95-
test('Navigate to /patch/2/child/1?foo=bar', async () => {
96-
await page.nuxt.navigate('/patch/2/child/1?foo=bar')
100+
test('Navigate to /patch/2/child/1?foo=bar', async () => {
101+
await page.nuxt.navigate('/patch/2/child/1?foo=bar')
97102

98-
expect(dates.patch).toBe(await page.$text('[data-date-patch]'))
99-
expect(dates.id).toBe(await page.$text('[data-date-id]'))
100-
expect(dates.child).toBe(await page.$text('[data-date-child]'))
101-
expect(dates.slug).toBe(await page.$text('[data-date-child-slug]'))
103+
expect(dates.patch).toBe(await page.$text('[data-date-patch]'))
104+
expect(dates.id).toBe(await page.$text('[data-date-id]'))
105+
expect(dates.child).toBe(await page.$text('[data-date-child]'))
106+
expect(dates.slug).toBe(await page.$text('[data-date-child-slug]'))
107+
})
108+
109+
test('Search a country', async () => {
110+
const countries = await page.$$text('[data-test-search-result]')
111+
expect(countries.length).toBe(5)
112+
113+
await page.type('[data-test-search-input]', 'gu')
114+
115+
await waitFor(250)
116+
const newCountries = await page.$$text('[data-test-search-result]', true)
117+
expect(newCountries.length).toBe(1)
118+
expect(newCountries).toEqual(['Guinea'])
119+
expect(await page.nuxt.routeData()).toEqual({
120+
path: '/patch/2/child/1',
121+
query: {
122+
foo: 'bar',
123+
q: 'gu'
124+
}
125+
})
126+
})
102127
})
103128

104-
test('Search a country', async () => {
105-
const countries = await page.$$text('[data-test-search-result]')
106-
expect(countries.length).toBe(5)
107-
108-
await page.type('[data-test-search-input]', 'gu')
109-
110-
await waitFor(250)
111-
const newCountries = await page.$$text('[data-test-search-result]', true)
112-
expect(newCountries.length).toBe(1)
113-
expect(newCountries).toEqual(['Guinea'])
114-
expect(await page.nuxt.routeData()).toEqual({
115-
path: '/patch/2/child/1',
116-
query: {
117-
foo: 'bar',
118-
q: 'gu'
119-
}
129+
describe('reuse child component if param is changed but watchParam is false', () => {
130+
test('Navigate to /patch/2/reuse', async () => {
131+
await page.nuxt.navigate('/patch/2/reuse')
132+
dates.slug = await page.$text('[data-date-slug]')
133+
134+
expect(dates.patch).toBe(await page.$text('[data-date-patch]'))
135+
expect(dates.id).toBe(await page.$text('[data-date-id]'))
136+
expect(+dates.child > +dates.id).toBe(true)
137+
})
138+
139+
test('Navigate to /patch/2/reuse/1', async () => {
140+
await page.nuxt.navigate('/patch/2/reuse/1')
141+
142+
expect(dates.patch).toBe(await page.$text('[data-date-patch]'))
143+
expect(dates.id).toBe(await page.$text('[data-date-id]'))
144+
expect(dates.slug).toBe(await page.$text('[data-date-slug]'))
145+
})
146+
147+
test('Navigate to /patch/2/reuse/2', async () => {
148+
await page.nuxt.navigate('/patch/2/reuse/2')
149+
150+
expect(dates.patch).toBe(await page.$text('[data-date-patch]'))
151+
expect(dates.id).toBe(await page.$text('[data-date-id]'))
152+
expect(dates.slug).toBe(await page.$text('[data-date-slug]'))
120153
})
121154
})
122155

test/fixtures/children/layouts/patch.vue

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,21 @@
4242
/patch/2/child/1?query=true#test
4343
</NuxtLink>
4444
</li>
45+
<li>
46+
<NuxtLink data-test-id="patch-id-2-reuse" to="/patch/2/reuse">
47+
/patch/2/reuse
48+
</NuxtLink>
49+
</li>
50+
<li>
51+
<NuxtLink data-test-id="patch-id-2-reuse-2" to="/patch/2/reuse/1">
52+
/patch/2/reuse/1
53+
</NuxtLink>
54+
</li>
55+
<li>
56+
<NuxtLink data-test-id="patch-id-2-reuse-2" to="/patch/2/reuse/2">
57+
/patch/2/reuse/2
58+
</NuxtLink>
59+
</li>
4560
</ul>
4661
</div>
4762
</template>
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<template>
2+
<div>
3+
<h4>
4+
_slug: <i data-date-slug>
5+
{{ date }}
6+
</i>
7+
</h4>
8+
</div>
9+
</template>
10+
11+
<script>
12+
export default {
13+
watchParam: false,
14+
asyncData () {
15+
return {
16+
date: Date.now()
17+
}
18+
}
19+
}
20+
</script>

0 commit comments

Comments
 (0)