如何在SvelteKit的load函数外部获取fetch实现?规避组件层级传递
解决SvelteKit组件无需逐层传递fetch的方案
你完全可以不用逐层传递SvelteKit的fetch包装器,下面是几种简便的实现方式:
方案1:用Svelte上下文API传递fetch
通过上下文把load里的fetch存起来,所有子组件都能直接取,不用层层传props:
- 在页面的load函数中存入fetch:
// src/routes/[id]/+page.ts import { setContext } from 'svelte'; import type { PageLoad } from './$types'; export const load: PageLoad = async ({ fetch }) => { // 用唯一key把fetch存入上下文 setContext('sveltekit-fetch', fetch); // 其他load逻辑... return {}; };
- 在Address组件中直接获取:
<!-- src/lib/components/Address.svelte --> <script lang="ts"> import { getContext } from 'svelte'; import { findCityList, type ICity } from '$lib/city'; // 从上下文取fetch const svelteKitFetch = getContext<typeof fetch>('sveltekit-fetch'); let debounceSearchTimer: NodeJS.Timeout; async function searchCities(input: string): Promise<ICity[] | false> { return new Promise((resolve, reject) => { debounceSearchTimer = setTimeout(async () => { try { const options = await findCityList({ fetch: svelteKitFetch, pagination: { /* 你的分页参数 */ }, searchOptions: { input } }); // 处理结果逻辑... resolve(options); } catch (e) { console.error('获取城市列表失败', e); reject(e); } }, 750); }); } </script>
方案2:封装全局API工具,默认用SvelteKit的fetch
直接在$lib里封装API调用函数,把fetch设为可选参数,默认用全局的fetch(SvelteKit在客户端和服务端都会自动提供符合要求的fetch实例):
// src/lib/city.ts import type { ICity } from './types'; export async function findCityList({ fetch = globalThis.fetch, // 默认用全局fetch pagination, searchOptions }: { fetch?: typeof globalThis.fetch; pagination: { /* 分页类型定义 */ }; searchOptions: { input: string }; }): Promise<ICity[]> { const response = await fetch('/endpoint.json', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ query: `/* 你的GraphQL查询语句 */`, variables: { pagination, searchOptions } }) }); if (!response.ok) throw new Error('请求失败'); const data = await response.json(); return data.data.cities; }
之后在Address组件里直接调用,不用传fetch:
<!-- src/lib/components/Address.svelte --> <script lang="ts"> import { findCityList, type ICity } from '$lib/city'; let debounceSearchTimer: NodeJS.Timeout; async function searchCities(input: string): Promise<ICity[] | false> { return new Promise((resolve, reject) => { debounceSearchTimer = setTimeout(async () => { try { const options = await findCityList({ pagination: { /* 你的分页参数 */ }, searchOptions: { input } }); // 处理结果逻辑... resolve(options); } catch (e) { console.error('获取城市列表失败', e); reject(e); } }, 750); }); } </script>
方案3:客户端组件直接用全局fetch
如果你的Address是客户端组件(比如加了client:only指令),SvelteKit会自动在全局注入包装后的fetch,和load里的fetch行为完全一致(自动解析相对路径、携带认证凭证等),直接用就行。
注意点
- 服务端组件调用API时,还是要从load传fetch或者用上下文方案;
- 上下文方案适合多层级组件共享fetch的场景,避免props冗余;
- 全局封装方案最简洁,适合大多数通用API调用场景。
内容的提问来源于stack exchange,提问作者Sten Ka Razin
相关产品推荐
相关产品推荐

