How To Pass Data From Layout Page To descendant pages and components In SvelteKit

Overview

In the previous article, we went over how to create a standalone endpoint and fetch data from it in a layout and its descendant page. We specifically used a loading input stuff to access the fetched data.

But there are other ways to pass data around in SvelteKit and we will go over them in this article. In order for this article to be comprehensive, I will breifly go over stuff again:

  • Context
  • Stuff
  • Direct import

Getting Started

Terminal
npm init svelte@next sveltekit-tutorial
cd sveltekit-tutorial
vim .
npm install
npm run dev
sveltekit

1. Context

In Svelte and SvelteKit, any components can communicate with each other using Context API. By using it, you don't need to pass data and functions as props, or creating a lot of events to make pages and components to talk to each other.

Let's create __layout.svelte to work on our first example:

In the following layout page, we set context with a parent object.

./src/__layout.svelte
1<script>
2 import { setContext } from "svelte";
3
4 const parent = { name: "John", email: "john@example.com" };
5
6 setContext("parent", parent);
7</script>
8
9<h1>Parent</h1>
10
11<slot />

Here we simpley import our grandchild component.

./src/index.svelte
1<script>
2 import Grandchild from "$lib/Grandchild.svelte";
3</script>
4
5<h2>Child</h2>
6
7<Grandchild />

In this grandchild component, we use getContext() to access parent.

./src/lib/Grandchild.svelte
1<script>
2 import { getContext } from "svelte";
3
4 const parent = getContext("parent");
5</script>
6
7<h3>Grand Child</h3>
8
9<pre>{JSON.stringify(parent)}</pre>

Make sure to spin up dev server and access http://localhost:3000 in a browser:

sveltekit

2. Stuff

In SvelteKit, the load function receives the following six objects as the function arguments:

  • url
  • params
  • props
  • fetch
  • session
  • stuff

We are particularly interested in stuff.

In this layout page, we hard-code a parent object having a name and an email properties and attach it to the stuff. This stuff will be available to any subsequent load functions in the descendant layouts and pages.

./src/__layout.svelte
1<script context="module">
2 export const load = () => {
3 const parent = { name: "John", email: "john@example.com" };
4
5 return {
6 props: {},
7 stuff: {
8 parent,
9 },
10 };
11 };
12</script>
13
14<h1>Parent</h1>
15
16<slot />

To be able to access stuff in a descendant page, we need to use load() and stuff to extract the parent object and attach it to props. Then we export parent as a variable in the second <script> tag:

./src/index.svelte
1<script context="module">
2 export async function load({ stuff }) {
3 const { parent } = stuff;
4
5 return {
6 props: {
7 parent,
8 },
9 };
10 }
11</script>
12
13<script>
14 import Grandchild from "$lib/Grandchild.svelte";
15 export let parent;
16</script>
17
18<h2>Child</h2>
19
20<pre>{JSON.stringify(parent)}</pre>
21
22<Grandchild />
./src/lib/Grandchild.svelte
1<h3>Grand Child</h3>

Make sure to spin up dev server and access http://localhost:3000 in a browser:

sveltekit

Using page intead of load() to access stuff

stuff is also available to pages, components using the page stores. Here is how you do it. Change index.svelte while __layout.svelte, Grandchild.svelte kept same as above:

./src/routes/index.svelte
1<script>
2 import { page } from "$app/stores";
3 import Grandchild from "$lib/Grandchild.svelte";
4
5 export const { parent } = $page.stuff;
6</script>
7
8<h2>Child</h2>
9
10<pre>{JSON.stringify(parent)}</pre>
11
12<Grandchild />

Make sure to spin up dev server and access http://localhost:3000 in a browser:

sveltekit

3. Direct Import

What if you want to access props, stuff in a grandchild component directly? Remember that we can't use load() mainly because it is available to be used in pages and layouts only, not in components. Then you can simply use a direct import in a component to access data. That is to import load from the layout page and call it as a function in a component.

Now let's go over how we can directly import data from __layout.svelte to Grandchild.svelte component.

./src/routes/__layout.svelte
1<script context="module">
2 export const parent = { name: "John", email: "john@example.com" };
3
4 export const load = () => {
5 return {
6 props: {
7 foo: "bar",
8 },
9 stuff: {
10 parent,
11 },
12 };
13 };
14</script>
15
16<h1>Parent</h1>
17
18<slot />

In index.svelte, we simply use load() and stuff to access data from the layout page.

./src/routes/index.svelte
1<script context="module">
2 export async function load({ stuff }) {
3 const { parent } = stuff;
4
5 return {
6 props: {
7 parent,
8 },
9 };
10 }
11</script>
12
13<script>
14 import Grandchild from "$lib/Grandchild.svelte";
15 export let parent;
16</script>
17
18<h2>Child</h2>
19
20<pre>{JSON.stringify(parent)}</pre>
21
22<Grandchild />

In a grandchild component, instead of using load and stuff that are not available for components, you can import data and load function from the layout page and call it inside a component.

./src/lib/Grandchild.svelte
1<script>
2 // import parent, load directly from the layout page
3 import { parent, load } from "../routes/__layout.svelte";
4</script>
5
6<h3>Grand Child</h3>
7
8// Use parent and call load() directly to access data
9<pre>parent:{JSON.stringify(parent)}</pre>
10<pre>props:{JSON.stringify(load().props)}</pre>
11<pre>props:{JSON.stringify(load().stuff)}</pre>

Make sure to spin up dev server and access http://localhost:3000 in a browser:

sveltekit

Comments

© 2022 Youngjae Jay Lim. All Rights Reserved, Built with Gatsby