Data Fetching
React developers fetch data in useEffect (or hand it to React Query / SWR). Svelte has two approaches that map cleanly to what you already know:
onMount+fetch— client-side fetching; runs after the component mounts, just likeuseEffectwith an empty dependency array- SvelteKit
loadfunction — in+page.tsor+page.server.ts, returns data to the page component before render; the server-side equivalent of Next.jsgetServerSideProps
The big win: onMount is a simple function call with no dependency array to manage, and SvelteKit’s load runs on the server so there is no client-side loading flash for initial data.
useEffect + fetch vs onMount + fetch
Section titled “useEffect + fetch vs onMount + fetch”function PostList() { const [posts, setPosts] = React.useState([]); const [loading, setLoading] = React.useState(true); const [error, setError] = React.useState(null);
React.useEffect(() => { let cancelled = false; fetch('/api/posts') .then(r => r.json()) .then(data => { if (!cancelled) { setPosts(data); setLoading(false); } }) .catch(err => { if (!cancelled) { setError(err.message); setLoading(false); } }); return () => { cancelled = true; }; }, []);
if (loading) return <p>Loading...</p>; if (error) return <p>Error: {error}</p>; return <ul>{posts.map(p => <li key={p.id}>{p.title}</li>)}</ul>;}<script> import { onMount } from 'svelte';
let posts = $state([]); let loading = $state(true); let error = $state(null);
onMount(async () => { try { const res = await fetch('/api/posts'); posts = await res.json(); } catch (e) { error = e.message; } finally { loading = false; } });</script>
{#if loading} <p>Loading...</p>{:else if error} <p>Error: {error}</p>{:else} <ul> {#each posts as post} <li>{post.title}</li> {/each} </ul>{/if}Note: onMount runs once after mount. For one-shot fetches you do not need a cancellation flag — the component is already mounted. If you navigate away before the fetch resolves, reassigning $state after destruction is a no-op. Run this pattern in a SvelteKit project.
getServerSideProps vs SvelteKit load
Section titled “getServerSideProps vs SvelteKit load”// Next.js pages/posts.tsxexport async function getServerSideProps(context) { const res = await fetch('https://api.example.com/posts'); const posts = await res.json(); return { props: { posts } };}
export default function Posts({ posts }) { return ( <ul> {posts.map(p => <li key={p.id}>{p.title}</li>)} </ul> );}// +page.server.tsexport async function load({ fetch }) { const res = await fetch('https://api.example.com/posts'); const posts = await res.json(); return { posts };}
// +page.svelte — data is injected automatically<script> let { data } = $props();</script>
<ul> {#each data.posts as post} <li>{post.title}</li> {/each}</ul>SvelteKit’s load function receives an enhanced fetch that works on both server and client, handles cookies, and is automatically available — no import needed. Run this pattern in a SvelteKit project.
Try it: simulated fetch
Section titled “Try it: simulated fetch”Live network requests are unreliable in the sandbox. This demo simulates a 600 ms API call with setTimeout — the same $state + onMount pattern you’d use with real fetch.