sveltesvelte-3sveltekit

SvelteKit - load() not called from component but works as a Page


If the file test.svelte below is a Page in /routes, it successfully calls load() and populates the template with the JSON array it retrieves when I access it via http://localhost:3000/test. If I move this file to /lib and import it as a component in /routes/index.svelte, the load() method of the component never runs when I go to http://localhost:3000.

test.svelte

<script context="module" lang="ts">
  /**
     * @type {import('@sveltejs/kit').Load}
   */
  export async function load({ fetch }) {
    const url = '/api/announcement'
    const res: Response = await fetch(url)

    if (res.ok) {
      const sections: Announcement[] = await res.json()
      return {
        props: {
          sections
        }
      }
    }

    return {
      status: res.status,
      error: new Error(`Could not load ${url}`)
     }
  }
</script>

<script lang="ts">
  export let sections: Announcement[] = []
</script>

<template>
  {#each sections as section}
    <p>
      {section.title}<br/>
      {section.description}
    </p>
  {/each}
</template>

Here is routes/index.svelte that tries to load it as a component from /lib:

<script context="module" lang="ts">
  import Test from '$lib/test.svelte'
</script>

<template lang="pug">
  .container
    Test
</template>

Seems like I'm doing something obviously wrong but I'm new to Svelte and SvelteKit. While I considered retrieving the data in routes/index.svelte and pass it down to the component, I was hoping to encapsulate the data retrieval in the component to keep it simpler.


Solution

  • The docs state (emphasis mine)

    A component that defines a page or a layout can export a load function that runs before the component is created.

    This means you cannot use the load function in a regular component.

    You can however still use onMount, to load data when the component is mounted.

    Alternatively, you keep the load function in your page and pass the retrieved values to the component itself.

    If you really do not want a large load function in your page, you can also put it in a third file (loader.js) and import it from there in the page (in the end the load function has to be in the page)

    <script context="module">
      import _load from './loader.js';
      export const load = _load;
    </script>
    

    edit 31.5.2023

    The above solution works fine for SvelteKit on the date of the answer, in later version the load function has been extracted to it's own file +page.js (or +layout.js) for which the details can be found in the documentation.
    The basic principle however stays the same: loading data is for pages and layouts only, components take their data from props (or alternatively from a fetch in the onMount)