Skip to content

Commit e049174

Browse files
committed
fix(svelte-5): resolve race conditions
1 parent a2f63db commit e049174

1 file changed

Lines changed: 45 additions & 47 deletions

File tree

svelte-5/App.svelte

Lines changed: 45 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,61 @@
11
<script lang="ts">
2-
import type { User } from "jsonplaceholder-types/types/user";
2+
/// <reference types="svelte" />
33
import type { Post } from "jsonplaceholder-types/types/post";
4+
import type { User } from "jsonplaceholder-types/types/user";
45
56
const urlBase = "https://jsonplaceholder.typicode.com";
67
78
let selectedUserId = $state<number | undefined>(undefined);
8-
const users = $state<{ value: User[] | undefined; loading: boolean }>({
9-
value: undefined,
10-
loading: false,
11-
});
12-
const posts = $state<{ value: Post[] | undefined; loading: boolean }>({
13-
value: undefined,
14-
loading: false,
15-
});
9+
const users = $state<{
10+
value?: User[];
11+
loading: boolean;
12+
}>({ loading: false });
13+
const posts = $state<{
14+
value?: Post[];
15+
loading: boolean;
16+
}>({ loading: false });
1617
17-
$effect(() => {
18+
async function fetchUsers(signal: AbortSignal) {
1819
users.loading = true;
19-
const controller = new AbortController();
20+
try {
21+
const response = await fetch(`${urlBase}/users`, { signal });
22+
const data = (await response.json()) as User[];
23+
users.value = data;
24+
users.loading = false;
25+
} catch (error) {
26+
if (signal.aborted) return;
27+
users.loading = false;
28+
throw error;
29+
}
30+
}
2031
21-
fetch(`${urlBase}/users`, { signal: controller.signal })
22-
.then(async (response) => {
23-
users.value = await response.json();
24-
})
25-
.catch((error) => {
26-
if (!(error instanceof DOMException && error.name === "AbortError")) {
27-
throw error;
28-
}
29-
})
30-
.finally(() => {
31-
users.loading = false;
32+
async function fetchPosts(userId: number, signal: AbortSignal) {
33+
posts.loading = true;
34+
try {
35+
const response = await fetch(`${urlBase}/posts?userId=${userId}`, {
36+
signal,
3237
});
33-
34-
return () => controller.abort();
35-
});
36-
37-
$effect(() => {
38-
if (selectedUserId === undefined) {
39-
posts.value = undefined;
40-
return;
38+
const data = (await response.json()) as Post[];
39+
posts.value = data;
40+
posts.loading = false;
41+
} catch (error) {
42+
if (signal.aborted) return;
43+
posts.loading = false;
44+
throw error;
4145
}
42-
posts.loading = true;
43-
const controller = new AbortController();
46+
}
4447
45-
fetch(`${urlBase}/posts?userId=${selectedUserId}`, {
46-
signal: controller.signal,
47-
})
48-
.then(async (response) => {
49-
posts.value = await response.json();
50-
})
51-
.catch((error) => {
52-
if (!(error instanceof DOMException && error.name === "AbortError")) {
53-
throw error;
54-
}
55-
})
56-
.finally(() => {
57-
posts.loading = false;
58-
});
48+
$effect(function updateUsers() {
49+
const ctrl = new AbortController();
50+
fetchUsers(ctrl.signal);
51+
return () => ctrl.abort();
52+
});
5953
60-
return () => controller.abort();
54+
$effect(function updatePosts() {
55+
if (selectedUserId === undefined) return;
56+
const ctrl = new AbortController();
57+
fetchPosts(selectedUserId, ctrl.signal);
58+
return () => ctrl.abort();
6159
});
6260
</script>
6361

0 commit comments

Comments
 (0)