I would like to make a component in SvelteKit which has a randomized parameter. The problem is that the value this parameter takes is different for when the page is rendered server-side versus when that page becomes hydrated.
For example, consider this component:
<script>
export let t = Math.random() * 90
export let l = Math.random() * 90
</script>
<div class="box" style="--t: {t}vh; --l: {l}vw;"></div>
<style>
.box {
position: fixed;
top: var(--t); left: var(--l);
width: 10vw; height: 10vh;
background-color: black;
transition: all 1s;
}
</style>
When the page is rendered on the server, t
and l
take on some random value, and the result is returned to the browser as HTML. However, once the page becomes hydrated, t
and l
take on different values. As a result, the box moves.
I don't want the box to move; rather, I want the random value returned by the server to be used by the client as well so there isn't a flash of changing style. Everything's fine if the page is navigated via the in-page router; it's when the page is server-rendered that the box moves.
The result is the same if I export a load
function. Is there a way with SvelteKit for the server and client to agree on a random value?
You have a few options here:
<script>
import { onMount } from 'svelte';
let t, l;
onMount(() => {
t = Math.random() * 90;
l = Math.random() * 90;
})
</script>
{#if t && l }
<div class="box" style="--t: {t}vh; --l: {l}vw;"></div>
{/if}
<style>
.box {
position: fixed;
top: var(--t); left: var(--l);
width: 10vw; height: 10vh;
background-color: black;
transition: all 1s;
}
</style>
// random.json.js
export async function get() {
return {
body: {
t: Math.random() * 90,
l: Math.random() * 90,
},
};
}
<!-- index.svelte -->
<script context="module">
export async function load({ fetch }) {
// this will be cached, so it will be the same on client & server
const result = await fetch('/random.json');
const { t, l } = await result.json();
return {
props: {
t, l
}
}
}
</script>
<script>
export let t;
export let l;
</script>
<div class="box" style="--t: {t}vh; --l: {l}vw;"></div>
<style>
.box {
position: fixed;
top: var(--t); left: var(--l);
width: 10vw; height: 10vh;
background-color: black;
transition: all 1s;
}
</style>
Personally, I like the second option better, since there's no FOUC.