如何在非页面类SvelteKit组件中正确获取数据
问题原因
你遇到的渲染异常和响应式更新、onMount执行时机没有关系,核心问题是声明aircrafts变量时没有设置初始值:组件首次渲染时onMount钩子还未执行,此时aircrafts值为undefined,直接读取undefined.length就会出现你看到的报错。onMount内的赋值本身是可以正常触发Svelte响应式更新的。
解决方案
根据业务场景选择对应实现即可:
方案1:修复客户端onMount拉取逻辑(适合非首屏核心内容)
如果这个组件不是首屏必须立刻展示的内容(比如折叠面板、弹窗、延迟加载的侧边模块),直接给变量设置初始值,补充加载、错误状态判断即可:
<script lang="ts"> import { onMount } from 'svelte' import type { Aircraft } from '$lib/models' // 初始化空数组,避免首次渲染读取属性报错 let aircrafts: Aircraft[] = [] let loading = true let err: string | null = null onMount(async () => { try { const res = await fetch('/aircrafts') if (!res.ok) throw new Error('数据请求失败') aircrafts = await res.json() } catch (e) { err = e instanceof Error ? e.message : '加载失败' } finally { loading = false } }) </script> {#if loading} <p>加载中...</p> {:else if err} <p class="error">{err}</p> {:else} <p>{aircrafts.length} Aircraft</p> {/if}
这个写法的缺点是请求只会在客户端组件挂载后发起,SSR阶段拿不到对应数据,首屏会先出现加载态,存在请求瀑布流。
方案2:页面load预取+props传值(SvelteKit官方推荐最佳实践,适合首屏核心组件)
SvelteKit本身设计就是只有页面/布局组件支持load函数做服务端/客户端预取,可复用组件不需要自己耦合数据拉取逻辑:
- 首先把数据拉取逻辑抽成公共函数放到
$lib目录下,避免重复代码
// $lib/api/aircraft.ts import type { Aircraft } from '$lib/models' import type { Fetch } from '@sveltejs/kit' export async function getAircrafts(fetch: Fetch): Promise<Aircraft[]> { const res = await fetch('/aircrafts') if (!res.ok) throw new Error('航空器数据加载失败') return res.json() }
- 在使用该组件的页面/布局的
load函数中调用公共方法拉取数据,通过props传给组件
// 对应页面的+page.ts import { getAircrafts } from '$lib/api/aircraft' import type { PageLoad } from './$types' export const load: PageLoad = async ({ fetch }) => { return { aircrafts: await getAircrafts(fetch) } }
- 组件本身只负责接收props渲染,不需要自己处理请求逻辑
<script lang="ts"> import type { Aircraft } from '$lib/models' export let aircrafts: Aircraft[] </script> <p>{aircrafts.length} Aircraft</p>
这种方式可以享受SvelteKit自带的SSR、数据预取、请求去重能力,不会出现客户端请求瀑布流,首屏体验最好,组件本身也更易测试和复用。
内容的提问来源于stack exchange,提问作者Clifton Labrum
相关产品推荐
相关产品推荐

