sveltesveltekitflowbite-svelte

SvelteKit - Nested Prop Cannot read properties of undefined (reading 'whatever')


Simply I don't get it. I store fetch result in writable store and retrieve those data, but I got undefined error when I want to use nested json data (school) see below. Why?

    <p>item: {$data.item}</p>           <--- OK!
    <p>address: {$data.address}</p>     <--- OK!
    <p>school: {$data.city.school}</p>  <--- PROBLEM: Undefined. Why? simple nested json...

Json structure:

{
"item": "whatever",
"address": "address",
"city": {
"school": "school"
}

}

export default function fetchData() {
    const loading = writable(false)
    const error = writable(false)
    const data = writable({})
    let clear;
    async function getData() {
        loading.set(true)
        error.set(false)
        try {
            const response = await fetch('http://endpoint')
            data.set(await response.json())
        } catch(e) {
            error.set(e)
        }
        loading.set(false)
    }
  
  clearInterval(clear)
  clear = setInterval(getData, 5000)

    return [ data, loading, error, getData]
}

In svelte file:

<script>
    import snapshotStore from '../stores/dataStore';
    const [data, loading, error, getData] = dataStore();
</script>

<p>item: {$data.item}</p>           
<p>address: {$data.address}</p>    
<p>school: {$data.city.school}</p> <--- Problem, undefined.

Solution

  • The store is initialized like this:

    const data = writable({})
    

    Any access like $data.item will initially just return undefined and not cause errors, but $data.city.school will try access the school property on undefined.

    Either make the access safe (e.g. $data.city?.school or wrap things in {#if}), or initialize the store in a way that allows for this access without error, e.g.

    const data = writable({ city: { } })
    

    {#if} guards based on $loading and $error should also work, if the API is guaranteed to send the correct JSON (i.e. the city object always exists).

    {#if $loading}
      ...
    {:else if $error}
      ...
    {:else}
      <p>item: {$data.item}</p>           
      <p>address: {$data.address}</p>    
      <p>school: {$data.city.school}</p>
    {/if}