update docs

This commit is contained in:
Rich Harris
2019-04-30 12:10:53 -04:00
parent bca88831da
commit dc73973d44
13 changed files with 175 additions and 229 deletions

View File

@@ -2,46 +2,37 @@
title: Preloading
---
As seen in the [routing](guide#routing) section, top-level page components can have a `preload` function that will load some data that the page depends on. This is similar to `getInitialProps` in Next.js or `asyncData` in Nuxt.js.
As seen in the [routing](docs#routing) section, page components can have an optional `preload` function that will load some data that the page depends on. This is similar to `getInitialProps` in Next.js or `asyncData` in Nuxt.js.
```html
<script>
export default {
preload({ params, query }) {
const { slug } = params;
<script context="module">
export async function preload(page, session) {
const { slug } = page.params;
return this.fetch(`blog/${slug}.json`).then(r => r.json()).then(article => {
return { article };
});
}
};
const res = await this.fetch(`blog/${slug}.json`);
const article = await res.json();
return { article };
}
</script>
```
Your `preload` function is optional; whether or not you include it, the component will have access to the `query` and `params` objects, on top of any [default data](https://svelte.technology/guide#default-data) specified with a `data` property.
The top-level `_layout.html` component is rendered with a `preloading` value: `true` during preloading, `false` otherwise. This value is useful to display a loading spinner or otherwise indicate that a navigation is in progress.
```html
<!-- src/routes/_layout.html -->
{#if preloading}
<div>Loading...</div>
{/if}
<svelte:component this={child.component} {...child.props}/>
```
The `preloading` value is only set during page navigations. Prefetching (see [below](guide#prefetching)) does not set `preloading` since it is intended to be transparent to the user.
It lives in a `context="module"` script — see the [tutorial](https://svelte.dev/tutorial/module-exports) — because it's not part of the component instance itself; instead, it runs *before* the component is created, allowing you to avoid flashes while data is fetched.
### Argument
The `preload` function receives a `{ params, query }` object where `params` is derived from the URL and the route filename, and `query` is an object of values in the query string.
The `preload` function receives two arguments — `page` and `session`.
So if the example above was `src/routes/blog/[slug].html` and the URL was `/blog/some-post?foo=bar&baz`, the following would be true:
`page` is a `{ path, params, query }` object where `path` is the URL's pathname, `params` is derived from `path` and the route filename, and `query` is an object of values in the query string.
* `params.slug === 'some-post'`
* `query.foo === 'bar'`
* `query.baz === true`
So if the example above was `src/routes/blog/[slug].svelte` and the URL was `/blog/some-post?foo=bar&baz`, the following would be true:
* `page.path === '/blog/some-post'`
* `page.params.slug === 'some-post'`
* `page.query.foo === 'bar'`
* `page.query.baz === true`
`session` is generated on the server by the `session` option passed to `sapper.middleware` (TODO this needs further documentation. Perhaps a server API section?)
### Return value
@@ -52,14 +43,12 @@ When Sapper renders a page on the server, it will attempt to serialize the resol
### Context
Inside `preload`, you have access to three methods...
Inside `preload`, you have access to three methods:
* `this.fetch(url, options)`
* `this.error(statusCode, error)`
* `this.redirect(statusCode, location)`
...and `this.store`, if you're using [state management](guide#state-management).
#### this.fetch
@@ -68,16 +57,14 @@ In browsers, you can use `fetch` to make AJAX requests, for getting data from yo
To fix this, Sapper provides `this.fetch`, which works on the server as well as in the client:
```html
<script>
export default {
preload() {
return this.fetch(`secret-data.json`, {
credentials: 'include'
}).then(r => {
// ...
});
}
};
<script context="module">
export async function preload() {
const res = await this.fetch(`secret-data.json`, {
credentials: 'include'
});
// ...
}
</script>
```
@@ -89,23 +76,19 @@ Note that you will need to use session middleware such as [express-session](http
If the user navigated to `/blog/some-invalid-slug`, we would want to render a 404 Not Found page. We can do that with `this.error`:
```html
<script>
export default {
preload({ params, query }) {
const { slug } = params;
<script context="module">
export async function preload({ params, query }) {
const { slug } = params;
return this.fetch(`blog/${slug}.json`).then(r => {
// assume all responses are either 200 or 404
if (r.status === 200) {
return r.json().then(article => {
return { article };
});
} else {
this.error(404, 'Not found');
}
});
const res = await this.fetch(`blog/${slug}.json`);
if (res.status === 200) {
const article = await res.json();
return { article };
}
};
this.error(404, 'Not found');
}
</script>
```
@@ -117,19 +100,15 @@ The same applies to other error codes you might encounter.
You can abort rendering and redirect to a different location with `this.redirect`:
```html
<script>
export default {
preload({ params, session }) {
const { user } = this.store.get();
<script context="module">
export async function preload(page, session) {
const { user } = session;
if (!user) {
return this.redirect(302, 'login');
}
return {
user
};
if (!user) {
return this.redirect(302, 'login');
}
};
return { user };
}
</script>
```