最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - SvelteKit Rendering a Random Prop is different between server and client - Stack Overflow

programmeradmin2浏览0评论

I would like to make a ponent 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 bees hydrated.

For example, consider this ponent:

<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 bees 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?

I would like to make a ponent 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 bees hydrated.

For example, consider this ponent:

<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 bees 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?

Share Improve this question asked Jan 14, 2022 at 17:34 AuroratideAuroratide 2,63213 silver badges21 bronze badges 1
  • 1 I believe trying to reconcile server- and client-side values will be difficult if possible at all. I would instead prevent one or the other. You could set the values inside onMount to prevent server-side putation, or you could turn hydration off for the page (it has to be a page however, not merely a ponent) to use server-side values (you'd have to also verify this doesn't negatively impact your client-side navigation behavior, though). – Thomas Hennes Commented Jan 14, 2022 at 18:18
Add a ment  | 

3 Answers 3

Reset to default 6

You have a few options here:

  1. Set the random numbers in onMount so they're only set on the client. This will cause a FOUC, however, since the box won't be server rendered.
<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>
  1. Generate the random numbers inside a server endpoint that you fetch in the load function. Since SvelteKit caches the result of fetches inside load, this should use the same random numbers on both client and server.
// 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.

You can use a .server.js/.server.ts file to create t and l only on the server side.

You have a file mypage.server.ts:

export const load = async () => {
    return { t: Math.random() * 90, l: Math.random() * 90};
};

And then in mypage.svelte:

<script>
    export let data;
    let { t, l } = data;
</script>
...

See also :

  • Section in Svelte tutorial
  • My mit fixing the same problem on my site

I think you could avoid a backend call and use a predictable pseudorandom number generator.

For example; https://github./davidbau/seedrandom

发布评论

评论列表(0)

  1. 暂无评论