SvelteKit 渲染随机 Prop 在服务器和客户端之间是不同的

Aur*_*ide 5 javascript server-side-rendering svelte sveltekit

我想在 SvelteKit 中制作一个具有随机参数的组件。问题在于,当页面在服务器端呈现时和页面变得水合时,此参数采用的值是不同的。

例如,考虑这个组件:

<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>
Run Code Online (Sandbox Code Playgroud)

当页面在服务器上呈现时,tl采用一些随机值,并将结果作为 HTML 返回到浏览器。然而,一旦页面变得水合,t就会l呈现不同的值。结果,盒子移动了。

我不想让盒子移动;相反,我希望客户端也使用服务器返回的随机值,这样就不会出现样式改变的情况。如果页面是通过页内路由器导航的,那么一切都很好;当页面由服务器渲染时,该框才会移动。

如果我导出一个函数,结果是一样的load。SvelteKit 有没有办法让服务器和客户端就随机值达成一致?

Geo*_*ich 5

您在这里有几个选择:

  1. 在 onMount 中设置随机数,以便它们仅在客户端上设置。然而,这将导致 FOUC,因为该框不会被服务器渲染。
<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>
Run Code Online (Sandbox Code Playgroud)
  1. 在加载函数中获取的服务器端点内生成随机数。由于 SvelteKit 会缓存加载内部获取的结果,因此应该在客户端和服务器上使用相同的随机数。
// random.json.js
export async function get() {
  return {
    body: {
      t: Math.random() * 90,
      l: Math.random() * 90,
    },
  };
}
Run Code Online (Sandbox Code Playgroud)
<!-- 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>
Run Code Online (Sandbox Code Playgroud)

就我个人而言,我更喜欢第二种选择,因为没有 FOUC。