How To Pass Data From Layout Page To descendant pages and components In SvelteKit
April 2nd, 2022
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
Terminalnpm init svelte@next sveltekit-tutorialcd sveltekit-tutorialvim .npm installnpm run dev
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.svelte1<script>2 import { setContext } from "svelte";34 const parent = { name: "John", email: "john@example.com" };56 setContext("parent", parent);7</script>89<h1>Parent</h1>1011<slot />
Here we simpley import our grandchild component.
./src/index.svelte1<script>2 import Grandchild from "$lib/Grandchild.svelte";3</script>45<h2>Child</h2>67<Grandchild />
In this grandchild component, we use getContext()
to access parent
.
./src/lib/Grandchild.svelte1<script>2 import { getContext } from "svelte";34 const parent = getContext("parent");5</script>67<h3>Grand Child</h3>89<pre>{JSON.stringify(parent)}</pre>
Make sure to spin up dev server and access http://localhost:3000
in a browser:
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.svelte1<script context="module">2 export const load = () => {3 const parent = { name: "John", email: "john@example.com" };45 return {6 props: {},7 stuff: {8 parent,9 },10 };11 };12</script>1314<h1>Parent</h1>1516<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.svelte1<script context="module">2 export async function load({ stuff }) {3 const { parent } = stuff;45 return {6 props: {7 parent,8 },9 };10 }11</script>1213<script>14 import Grandchild from "$lib/Grandchild.svelte";15 export let parent;16</script>1718<h2>Child</h2>1920<pre>{JSON.stringify(parent)}</pre>2122<Grandchild />
./src/lib/Grandchild.svelte1<h3>Grand Child</h3>
Make sure to spin up dev server and access http://localhost:3000
in a browser:
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.svelte1<script>2 import { page } from "$app/stores";3 import Grandchild from "$lib/Grandchild.svelte";45 export const { parent } = $page.stuff;6</script>78<h2>Child</h2>910<pre>{JSON.stringify(parent)}</pre>1112<Grandchild />
Make sure to spin up dev server and access http://localhost:3000
in a browser:
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.svelte1<script context="module">2 export const parent = { name: "John", email: "john@example.com" };34 export const load = () => {5 return {6 props: {7 foo: "bar",8 },9 stuff: {10 parent,11 },12 };13 };14</script>1516<h1>Parent</h1>1718<slot />
In index.svelte
, we simply use load()
and stuff
to access data from the layout page.
./src/routes/index.svelte1<script context="module">2 export async function load({ stuff }) {3 const { parent } = stuff;45 return {6 props: {7 parent,8 },9 };10 }11</script>1213<script>14 import Grandchild from "$lib/Grandchild.svelte";15 export let parent;16</script>1718<h2>Child</h2>1920<pre>{JSON.stringify(parent)}</pre>2122<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.svelte1<script>2 // import parent, load directly from the layout page3 import { parent, load } from "../routes/__layout.svelte";4</script>56<h3>Grand Child</h3>78// Use parent and call load() directly to access data9<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:
Comments