SvelteKit 渲染随机道具在服务器和客户端之间是不同的
SvelteKit Rendering a Random Prop is different between server and client
我想在 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>
当页面在服务器上呈现时,t
和 l
取一些随机值,结果作为 HTML 返回给浏览器。但是,一旦页面变得水合,t
和 l
就会呈现不同的值。结果,盒子移动了。
我不想让盒子移动;相反,我希望客户端也使用服务器返回的随机值,这样就不会突然改变样式。如果页面是通过页面内路由器导航的,一切都很好;当页面由服务器呈现时,方框就会移动。
如果我导出一个 load
函数,结果是一样的。 SvelteKit 有没有办法让服务器和客户端就随机值达成一致?
这里有几个选项:
- 在 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>
- 在加载函数中获取的服务器端点内生成随机数。由于 SvelteKit 缓存了加载中的提取结果,因此这应该在客户端和服务器上使用相同的随机数。
// 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>
就我个人而言,我更喜欢第二种选择,因为没有 FOUC。
我认为您可以避免后端调用并使用可预测的伪随机数生成器。
我想在 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>
当页面在服务器上呈现时,t
和 l
取一些随机值,结果作为 HTML 返回给浏览器。但是,一旦页面变得水合,t
和 l
就会呈现不同的值。结果,盒子移动了。
我不想让盒子移动;相反,我希望客户端也使用服务器返回的随机值,这样就不会突然改变样式。如果页面是通过页面内路由器导航的,一切都很好;当页面由服务器呈现时,方框就会移动。
如果我导出一个 load
函数,结果是一样的。 SvelteKit 有没有办法让服务器和客户端就随机值达成一致?
这里有几个选项:
- 在 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>
- 在加载函数中获取的服务器端点内生成随机数。由于 SvelteKit 缓存了加载中的提取结果,因此这应该在客户端和服务器上使用相同的随机数。
// 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>
就我个人而言,我更喜欢第二种选择,因为没有 FOUC。
我认为您可以避免后端调用并使用可预测的伪随机数生成器。