如何在SvelteKit的await块外部获取流式Promise值设置页面标题?
问题描述
我有一个+layout.server.ts文件,它执行API请求并将数据返回给同级的+layout.svelte。由于该请求可能需要一两秒,所以在Svelte代码中我将其值放在await块内,以便显示加载指示器。
这一切都正常工作,但现在我尝试将页面标题设置为已解析Promise中包含的值时遇到了困难。我无法在<title>标签中放置await块,也无法直接在Svelte代码中修改状态,请问是否有可行的实现方法?
参考代码
+layout.server.ts
import type { LayoutServerLoad } from "./$types"; import { getPlayer } from "$lib/utils"; export const load: LayoutServerLoad = async ({ params }) => { return { streamed: { player: getPlayer(params.username) } }; }
+layout.svelte(当前遇到问题的代码)
<script lang="ts"> import Header from "$lib/blocks/Header.svelte"; import type { LayoutProps } from "./$types"; let { data, children }: LayoutProps = $props(); let title = $state("Loading..."); function setTitle(newTitle: string) { title = newTitle; console.log(newTitle); } </script> <svelte:head> <title>{title}</title> </svelte:head> <div> <Header /> <div> {#await data.streamed.player} <p>Loading...</p> {:then player} {setTitle(player?.username || "Player not found!")} <p>{player?.username}</p> {:catch error} {setTitle("Player not found!")} <p>Problem loading player data!</p> {/await} </div> {@render children()} </div>
解决方案
这里有几种实用的实现方式:
方法1:直接在await块中更新状态
你当前的思路可以简化,不需要单独的setTitle函数,直接在模板的await块里修改title变量即可,Svelte允许在模板表达式中直接更新响应式状态:
<script lang="ts"> import Header from "$lib/blocks/Header.svelte"; import type { LayoutProps } from "./$types"; let { data, children }: LayoutProps = $props(); let title = $state("Loading..."); </script> <svelte:head> <title>{title}</title> </svelte:head> <div> <Header /> <div> {#await data.streamed.player} <p>Loading...</p> {:then player} {title = player?.username || "Player not found!"} <p>{player?.username}</p> {:catch error} {title = "Player not found!"} <p>Problem loading player data!</p> {/await} </div> {@render children()} </div>
方法2:用$effect监听流式数据变化
通过$effect在组件初始化时自动处理Promise,更新标题,无需在模板中额外处理:
<script lang="ts"> import Header from "$lib/blocks/Header.svelte"; import type { LayoutProps } from "./$types"; let { data, children }: LayoutProps = $props(); let title = $state("Loading..."); $effect(() => { (async () => { try { const player = await data.streamed.player; title = player?.username || "Player not found!"; } catch { title = "Player not found!"; } })(); }); </script> <svelte:head> <title>{title}</title> </svelte:head> <div> <Header /> <div> {#await data.streamed.player} <p>Loading...</p> {:then player} <p>{player?.username}</p> {:catch error} <p>Problem loading player data!</p> {/await} </div> {@render children()} </div>
方法3:用$derived生成异步标题
把标题逻辑封装成响应式异步变量,直接在<svelte:head>中用await块处理:
<script lang="ts"> import Header from "$lib/blocks/Header.svelte"; import type { LayoutProps } from "./$types"; let { data, children }: LayoutProps = $props(); const title = $derived(async () => { try { const player = await data.streamed.player; return player?.username || "Player not found!"; } catch { return "Player not found!"; } }); </script> <svelte:head> {#await title} <title>Loading...</title> {:then finalTitle} <title>{finalTitle}</title> {:catch} <title>Player not found!</title> {/await} </svelte:head> <div> <Header /> <div> {#await data.streamed.player} <p>Loading...</p> {:then player} <p>{player?.username}</p> {:catch error} <p>Problem loading player data!</p> {/await} </div> {@render children()} </div>
内容的提问来源于stack exchange,提问作者SirArchibald
相关产品推荐
相关产品推荐

