我正在开发一个 SvelteKit 项目,目标是实现通用渲染。我的目标是让第一个请求进行服务器端渲染(SSR),然后切换到客户端渲染(CSR)以进行后续导航。但是,我遇到了一个似乎无法解决的问题。
问题:
从一个页面导航到另一页面(例如,从主页导航到产品)时,只有完全获取目标页面的数据后才会进行导航。理想情况下,我希望目标页面立即加载并在获取数据时显示各个组件的加载器。这样,用户就不会在导航发生之前等待整个页面加载。
我尝试在组件中使用 Svelte 的 {#await ...} 块来实现此功能,但我面临着困境:
在加载函数中使用await: SSR 工作正常,但页面导航会延迟,直到获取数据为止。
在加载函数中跳过await: 导航立即发生,但 SSR 中断。
我的设置:
这是我正在使用的简化版本:
// +page.svelte
<script lang="ts">
let { data } = $props();
</script>
<h1>TODOS</h1>
{#await data.todos}
Loading ...
{:then todos}
{#each todos as todo}
<div>{todo.todo}</div>
{/each}
{/await}
// +page.ts
type Todo = {
id: number;
todo: string;
completed: boolean;
userId: number;
};
export async function load({ fetch }) {
const getTodos = () =>
fetch('https://dummyjson.com/todos')
.then(r => r.json())
.then((r): { todos: Todo[] } => r.todos);
return {
todos: getTodos(), // await getTodos()
};
}
// /产品/+page.svelte
<script lang="ts">
let { data } = $props();
</script>
<h1>Products</h1>
{#await data.products}
Loading ...
{:then products}
{#each products as product}
<div>{product.title}</div>
{/each}
{/await}
// /产品/+page.ts
type Product = {
id: number;
title: string;
};
export async function load({ fetch }) {
const getProducts = () =>
fetch('https://dummyjson.com/products')
.then(r => r.json())
.then(r => r.products as Product[]);
return {
products: getProducts(), // await getProducts(),
};
}
我在寻找什么:
有人设法解决这个问题,还是我缺少更好的方法?我很想获得一些建议或示例,了解如何在第一个请求时使用 SSR 正确实现通用渲染,并在之后使用各个组件加载器实现流畅的客户端导航。
P.S 我尝试过浏览器? getTodos() : 等待 getTodos() 但我遇到了水合不匹配错误
您可以尝试使用
isDataRequest
参数中的 PageServerLoad
。
export const load: PageServerLoad = async ({ isDataRequest, params }) => {
const data = get(params.id);
return {
data: isDataRequest ? data : await data,
};
}
有关流式承诺的链接文档:
https://kit.svelte.dev/docs/load#streaming-with-promises
然后使用异步块来显示骨架。
注意:它可能无法在开发模式下工作,因此请先构建站点。
您可以在本文中查看有关此方法的更多信息:
https://geoffrich.net/posts/conditionally-stream-data/\
(请记住,您不需要嵌套 Promise 对象,SvelteKit 1.x 行为)