Skip to content

Commit b0ffb4d

Browse files
authored
reset navigation store to null after aborted nav (#4664)
* reset navigation store to null after aborted nav * remove unused variable
1 parent 41db4a3 commit b0ffb4d

File tree

6 files changed

+48
-27
lines changed

6 files changed

+48
-27
lines changed

.changeset/six-garlics-film.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@sveltejs/kit': patch
3+
---
4+
5+
Navigation to current URL is no longer a no-op

.changeset/sour-penguins-admire.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@sveltejs/kit': patch
3+
---
4+
5+
navigation store resets to null after aborted nav

packages/kit/src/runtime/client/client.js

+9-26
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,6 @@ export function create_client({ target, session, base, trailing_slash }) {
121121
});
122122
ready = true;
123123

124-
/** Keeps tracks of multiple navigations caused by redirects during rendering */
125-
let navigating = 0;
126-
127124
let router_enabled = true;
128125

129126
// keeping track of the history index in order to prevent popstate navigation events if needed
@@ -158,9 +155,6 @@ export function create_client({ target, session, base, trailing_slash }) {
158155
/** @type {{}} */
159156
let token;
160157

161-
/** @type {{}} */
162-
let navigating_token;
163-
164158
/**
165159
* @param {string} href
166160
* @param {{ noscroll?: boolean; replaceState?: boolean; keepfocus?: boolean; state?: any }} opts
@@ -206,6 +200,7 @@ export function create_client({ target, session, base, trailing_slash }) {
206200
}
207201

208202
/**
203+
* Returns `true` if update completes, `false` if it is aborted
209204
* @param {URL} url
210205
* @param {string[]} redirect_chain
211206
* @param {boolean} no_cache
@@ -237,11 +232,11 @@ export function create_client({ target, session, base, trailing_slash }) {
237232

238233
if (!navigation_result) {
239234
await native_navigation(url);
240-
return; // unnecessary, but TypeScript prefers it this way
235+
return false; // unnecessary, but TypeScript prefers it this way
241236
}
242237

243238
// abort if user navigated during update
244-
if (token !== current_token) return;
239+
if (token !== current_token) return false;
245240

246241
invalidated.length = 0;
247242

@@ -263,7 +258,7 @@ export function create_client({ target, session, base, trailing_slash }) {
263258
await native_navigation(new URL(navigation_result.redirect, location.href));
264259
}
265260

266-
return;
261+
return false;
267262
}
268263
} else if (navigation_result.props?.page?.status >= 400) {
269264
const updated = await stores.updated.check();
@@ -346,6 +341,8 @@ export function create_client({ target, session, base, trailing_slash }) {
346341

347342
const leaf_node = navigation_result.state.branch[navigation_result.state.branch.length - 1];
348343
router_enabled = leaf_node?.module.router !== false;
344+
345+
return true;
349346
}
350347

351348
/** @param {import('./types').NavigationResult} result */
@@ -898,29 +895,20 @@ export function create_client({ target, session, base, trailing_slash }) {
898895

899896
accepted();
900897

901-
navigating++;
902-
903-
const current_navigating_token = (navigating_token = {});
904-
905898
if (started) {
906899
stores.navigating.set({
907900
from: current.url,
908901
to: normalized
909902
});
910903
}
911904

912-
await update(normalized, redirect_chain, false, {
905+
const completed = await update(normalized, redirect_chain, false, {
913906
scroll,
914907
keepfocus,
915908
details
916909
});
917910

918-
navigating--;
919-
920-
// navigation was aborted
921-
if (navigating_token !== current_navigating_token) return;
922-
923-
if (!navigating) {
911+
if (completed) {
924912
const navigation = { from, to: normalized };
925913
callbacks.after_navigate.forEach((fn) => fn(navigation));
926914

@@ -1113,11 +1101,6 @@ export function create_client({ target, session, base, trailing_slash }) {
11131101
// Ignore if <a> has a target
11141102
if (is_svg_a_element ? a.target.baseVal : a.target) return;
11151103

1116-
if (url.href === location.href) {
1117-
if (!location.hash) event.preventDefault();
1118-
return;
1119-
}
1120-
11211104
// Check if new url only differs by hash and use the browser default behavior in that case
11221105
// This will ensure the `hashchange` event is fired
11231106
// Removing the hash does a full page navigation in the browser, so make sure a hash is present
@@ -1142,7 +1125,7 @@ export function create_client({ target, session, base, trailing_slash }) {
11421125
redirect_chain: [],
11431126
details: {
11441127
state: {},
1145-
replaceState: false
1128+
replaceState: url.href === location.href
11461129
},
11471130
accepted: () => event.preventDefault(),
11481131
blocked: () => event.preventDefault()

packages/kit/test/apps/basics/src/routes/store/navigating/__layout.svelte

+5-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@
22
import { navigating } from '$app/stores';
33
</script>
44

5-
<nav><a href="/store/navigating/a">a</a> <a href="/store/navigating/b">b</a></nav>
5+
<nav>
6+
<a href="/store/navigating/a">a</a>
7+
<a href="/store/navigating/b">b</a>
8+
<a href="/store/navigating/c">c</a>
9+
</nav>
610

711
<div id="nav-status">
812
{#if $navigating}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<script context="module">
2+
/** @type {import('@sveltejs/kit').Load} */
3+
export async function load() {
4+
await new Promise((f) => setTimeout(f, 1000));
5+
return {};
6+
}
7+
</script>
8+
9+
<p>c</p>

packages/kit/test/apps/basics/test/test.js

+15
Original file line numberDiff line numberDiff line change
@@ -1696,6 +1696,21 @@ test.describe.parallel('$app/stores', () => {
16961696
expect(await page.textContent('#nav-status')).toBe('not currently navigating');
16971697
}
16981698
});
1699+
1700+
test('navigating store clears after aborted navigation', async ({ page, javaScriptEnabled }) => {
1701+
await page.goto('/store/navigating/a');
1702+
1703+
expect(await page.textContent('#nav-status')).toBe('not currently navigating');
1704+
1705+
if (javaScriptEnabled) {
1706+
page.click('a[href="/store/navigating/c"]');
1707+
await page.waitForTimeout(100); // gross, but necessary since no navigation occurs
1708+
page.click('a[href="/store/navigating/a"]');
1709+
1710+
await page.waitForSelector('#not-navigating', { timeout: 500 });
1711+
expect(await page.textContent('#nav-status')).toBe('not currently navigating');
1712+
}
1713+
});
16991714
});
17001715

17011716
test.describe.parallel('searchParams', () => {

0 commit comments

Comments
 (0)