Let's say I have a bunch of data docs that are JSON docs in S3, one per year. I have a route defined in Sapper via dir structure:
├── routes
│ ├── _error.svelte
│ ├── _layout.svelte
│ ├── about.svelte
│ ├── data
│ │ ├── [year].svelte
And the code in my script
block:
let yearData;
onMount(async () => {
const f = await fetch(yearDataUrl(year), {
headers: { 'Access-Control-Allow-Origin': '*' }
});
const jsonResults = await f.json();
yearData = jsonResults;
});
Each data set is in S3 as [s3 url]/[year here].json
. There are a set of links in the nav bar that show each data set. I can get the data to load in an onMount
fine, but subsequent clicks on the nav bar links don't load new data. So onMount
is probably the wrong choice.
How should I structure this? Also worth noting that I'd like to render these pages as static files down the road (the data changes rarely, especially for the previous years).
There are two options. The first and most idiomatic — and correct, in your situation, since it sounds like you want to use server-side rendering — is to use preload:
<script context="module">
export async function preload(page) {
const f = await this.fetch(yearDataUrl(page.params.year), {
headers: { 'Access-Control-Allow-Origin': '*' }
});
return {
yearData: await f.json()
};
}
</script>
<script>
export let yearData;
</script>
<!-- use yearData here -->
The preload function will run before the component is created, supplying it with the yearData
prop. Whenever page.params
changes, preload
will run again, setting a new prop.
Because this works on the server as well as on the client (hence the use of this.fetch
rather than fetch
, which works in both environments) you will get server-rendered pages, rather than a loading message that flickers into a page as soon as onMount
runs.
The second option, included for the sake of completeness, is to use the page store:
<script>
import { stores } from '@sapper/app';
const { page } = stores();
let yearData;
$: if (process.browser) {
fetch(yearDataUrl($page.params.year))
.then(f => f.json())
.then(data => {
yearData = data;
});
}
</script>
In this case yearData
won't be server-rendered. (To be complete, you would also need to handle race conditions and errors, which aren't an issue with preload
.)