I'm really struggling to understand reactivity in Svelte 5.
I've created a little class to encapsulate a data fetch operation:
class DataResponse {
data = $state([]);
error = $state();
isLoading = $state(false);
}
And a useFetchData
helper that kicks off a fetch and returns an instance of this class (which is updated by reassigning data
when the response is received).
export function useFetchData() {
const resp = new DataResponse();
async function fetchData() {
resp.isLoading = true;
try {
const response = await fetch("https://randomuser.me/api/?results=5");
const j = await response.json();
resp.data = j.results;
resp.error = undefined;
} catch (err) {
resp.error = err;
resp.data = undefined;
console.error(err);
} finally {
resp.isLoading = false;
}
}
fetchData();
return resp;
}
If I use this data directly at the call site, reactivity works as I'd expect and the UI updates when the API call returns.
<script>
import { useFetchData } from "./useFetchData.svelte.js";
const resp = useFetchData();
</script>
{#each response.data as person}
<div>{person.name.first} {person.name.last}</div>
{/each}
When I extract the UI logic into a separate component and try to pass this data to a child component as a prop, I lose reactivity and the UI never updates. What am I doing wrong?
<script>
import { useFetchData } from "./useFetchData.svelte.js";
const resp = useFetchData();
</script>
<People people={rest.data} />
<!-- People.svelte -->
<script>
let people = $props();
</script>
<h1>People</h1>
{#each people as person}
<div>{person.name.first} {person.name.last}</div>
{/each}
I've prepared a minimal example in the playground: https://svelte.dev/playground/455ad944b0cd42fdbee891a488ad372f?version=5.19.0
The props syntax in People
is off, you get all props as the object. You probably intended it to be this:
let { people } = $props();
You can also get all props and access the property separately if you want:
let props = $props();
{#each props.people as person} ...