Kip Olson
Kip Olson

Reputation: 51

How to pass reactive props from a SvelteKit __layout file to a page hosted in one of its slots?

The example below has two files: index.svelte is hosted in the slot provided in __layout.svelte. When you click the button it should change the color of the box in the hosted page. The code below works fine if index.svelte is a child component, but does not work if index.svelte is a page hosted in the slot. I am sure this is because props work differently with hosted pages.

I have tried using setContext/getContext and a writable store to pass the information across, but I have not found a way to make this reactive so that the box color change takes effect immediately - everything I have tried requires reloading index.svelte to apply the color change.

Is there a reactive way to update elements on the hosted page immediately?

__layout.svelte:

<script>
  let color = "green";

  function onClick(e) {
    color = "red";
  }
</script>

<button on:click={onClick}>Red</button>

<slot color={color}></slot>

index.svelte:

<script>
  export let color = "blue";
</script>

<div class="box" style="background-color:{color}"></div>

<style>
  .box {
    width: 100px;
    height: 100px;
    margin: 10px;
  }
</style>

Code above can be found here:

Example

Upvotes: 3

Views: 2098

Answers (1)

Stephane Vanraes
Stephane Vanraes

Reputation: 16411

You can create a store in the load function and pass this on one side to the layout and on the other side place in stuff.

<!-- __layout.svelte -->
<script context="module">
    import { writable } from 'svelte/store';
    export async function load() {
        const color = writable('green');

        return {
            props: {
                color
            },
            stuff: {
                color
            }
        };
    }
</script>

<script>
    export let color;

    function onClick(e) {
        $color = 'red';
    }
</script>

<button on:click={onClick}>Red</button>

<slot />

Then in the load function of the page itself, you grab this store from stuff and pass it on with the props.

<script context="module">
    export async function load({ stuff }) {
        return {
            props: {
                color: stuff.color
            }
        };
    }
</script>

<script>
    export let color;
</script>

<div class="box" style="background-color:{$color}" />

<style>
    .box {
        width: 100px;
        height: 100px;
        margin: 10px;
    }
</style>

Now you have reactivity!

a note on shared state and global stores

This works fine as described above, if you have a store that 'lives' outside of the load function this is considered shared state and will be common among all users, so be carefull with this.

<script context="module">
  import myStore from './myStore.js';
  export async function load() {
    myStore.set(something_sensitive); everyone has access to this now!!
  }
</script>

Upvotes: 2

Related Questions