【Svelte】如何使用 SvelteKit load 函数中的 depends 功能?例子演示

在 SvelteKit 中,load 事件中的 depends 函数用于声明你的 load 函数返回的数据(或其中一部分)依赖于一个特定的标识符(例如 URL 或自定义键)。

depends 的主要目的是允许你使用 $app/navigation 中的 invalidate(key) 从客户端选择性地重新运行 你的 load 函数(或使其特定部分失效)。这对于在不进行完整页面刷新的情况下更新当前页面上的数据非常有用,尤其是在用户操作(例如添加、更新或删除项目)改变了底层数据之后。

让我们通过一个例子来分解它:

场景: 我们想要显示一个"待办事项"列表。当用户通过同一页面上的表单添加新的待办事项时,我们希望待办事项列表能够自动刷新,而无需进行完整的页面导航。


示例:使用 depends 的待办事项列表

我们将创建一个简单的页面,用于显示待办事项并允许添加新的待办事项。

1. 项目设置(如果你还没有):

bash 复制代码
npm create svelte@latest my-sveltekit-app
cd my-sveltekit-app
npm install
# 建议选择 TypeScript 以获得类型安全,但它也适用于 JavaScript。

2. 创建文件:

复制代码
src/
├── routes/
│   ├── api/
│   │   └── todos/
│   │       └── +server.ts  <-- 我们的模拟待办事项 API
│   └── todos/
│       ├── +page.svelte     <-- Svelte 组件 (UI)
│       └── +page.ts         <-- 带有 depends 的 load 函数
└── app.d.ts

文件 1: src/routes/api/todos/+server.ts (模拟 API)

这将是我们的待办事项的简单内存"数据库"。

typescript 复制代码
// src/routes/api/todos/+server.ts
import { json } from '@sveltejs/kit';

interface Todo {
	id: number;
	text: string;
	completed: boolean;
}

// 模拟的待办事项数据
let todos: Todo[] = [
	{ id: 1, text: '学习 SvelteKit', completed: false },
	{ id: 2, text: '构建一个 SvelteKit 应用', completed: false }
];
let nextId = 3;

// GET 请求:返回所有待办事项
export async function GET() {
	return json(todos);
}

// POST 请求:添加一个新的待办事项
export async function POST(event) {
	const { text } = await event.request.json();
	if (!text) {
		return json({ error: 'Text is required' }, { status: 400 });
	}

	const newTodo: Todo = {
		id: nextId++,
		text,
		completed: false
	};
	todos.push(newTodo);

	return json(newTodo, { status: 201 });
}

文件 2: src/routes/todos/+page.ts (带有 dependsload 函数)

这就是我们使用 event.depends() 的地方。

typescript 复制代码
// src/routes/todos/+page.ts
import type { PageLoad } from './$types';

export const load: PageLoad = async ({ fetch, depends }) => {
	// 声明对 'api:todos' 键的依赖。
	// 这告诉 SvelteKit,此 load 函数返回的数据
	// 依赖于与 'api:todos' 关联的状态。
	depends('api:todos');

	// 从我们的模拟 API 获取待办事项
	const response = await fetch('/api/todos');
	const todos = await response.json();

	return {
		todos
	};
};

文件 3: src/routes/todos/+page.svelte (UI 组件)

此组件将显示待办事项并提供一个表单来添加新的待办事项。关键是,在添加待办事项后,它将调用 invalidate('api:todos')

svelte 复制代码
<!-- src/routes/todos/+page.svelte -->
<script lang="ts">
	import type { PageData } from './$types';
	import { invalidate } from '$app/navigation';

	export let data: PageData; // 来自 +page.ts 的数据类型

	let newTodoText = '';
	let loading = false;
	let error: string | null = null;

	async function addTodo() {
		loading = true;
		error = null;

		try {
			const response = await fetch('/api/todos', {
				method: 'POST',
				headers: {
					'Content-Type': 'application/json'
				},
				body: JSON.stringify({ text: newTodoText })
			});

			if (!response.ok) {
				const resData = await response.json();
				throw new Error(resData.error || 'Failed to add todo');
			}

			// !!! 奇迹发生在这里 !!!
			// 成功添加待办事项后,我们使 'api:todos' 依赖项失效。
			// 这告诉 SvelteKit 重新运行任何声明了对 'api:todos' 依赖关系的
			// load 函数。
			// 在我们的例子中,它将重新运行 `src/routes/todos/+page.ts`,重新获取列表。
			await invalidate('api:todos');

			newTodoText = ''; // 清空输入框
		} catch (e: any) {
			error = e.message;
		} finally {
			loading = false;
		}
	}
</script>

<svelte:head>
	<title>SvelteKit 待办事项</title>
</svelte:head>

<h1>我的待办事项</h1>

{#if data.todos.length === 0}
	<p>还没有待办事项!在下面添加一个。</p>
{:else}
	<ul>
		{#each data.todos as todo (todo.id)}
			<li>{todo.text} {todo.completed ? '(已完成)' : ''}</li>
		{/each}
	</ul>
{/if}

<form on:submit|preventDefault={addTodo}>
	<input type="text" bind:value={newTodoText} placeholder="添加一个新的待办事项..." required />
	<button type="submit" disabled={loading}>
		{loading ? '正在添加...' : '添加待办事项'}
	</button>
</form>

{#if error}
	<p style="color: red;">错误: {error}</p>
{/if}

<style>
	ul {
		list-style: none;
		padding: 0;
	}
	li {
		padding: 8px 0;
		border-bottom: 1px solid #eee;
	}
	li:last-child {
		border-bottom: none;
	}
	form {
		margin-top: 20px;
	}
	input {
		padding: 8px;
		margin-right: 10px;
		width: 250px;
	}
	button {
		padding: 8px 15px;
		cursor: pointer;
	}
</style>

工作原理:

  1. +page.ts (Load 函数):

    • depends('api:todos'):这一行是关键。它声明此 load 函数返回的数据依赖于标识符 'api:todos'。此键可以是任何字符串,但最佳实践是使其具有描述性(例如,scheme:path)。
    • 然后它从 /api/todos fetch (获取)当前的待办事项列表。
  2. +page.svelte (UI 组件):

    • 显示最初加载的 data.todos
    • 当"添加待办事项"表单提交时,调用 addTodo()
    • fetch('/api/todos', { method: 'POST', ... }) 将新的待办事项发送到我们的模拟 API。
    • await invalidate('api:todos');这是最关键的部分。 在新的待办事项成功添加到服务器后,我们调用 invalidate('api:todos')
      • SvelteKit 会检测到这个 invalidate 调用。
      • 然后它会检查所有声明了对 'api:todos' 依赖关系的活动 load 函数。
      • 在我们的例子中,它找到了 src/routes/todos/+page.ts
      • 然后它无需进行完整的页面导航 就重新运行该 load 函数。
      • +page.ts 重新获取更新后的待办事项列表(现在包含了新的待办事项)。
      • SvelteKit 无缝地更新 +page.svelte 中的 data 属性,并且 UI 会响应式地重新渲染以显示新的待办事项。

关键要点:

  • load 函数中使用 depends(key) 声明一个依赖关系。
  • $app/navigation 中使用 invalidate(key) 触发声明了对该特定 key 依赖的 load 函数(或相关部分)的重新运行。
  • key 格式: 使用描述性键,通常是 scheme:path(例如 api:usersdata:products:123todos:active)。
  • invalidate 的使用时机: 通常在数据修改操作(例如 POSTPUTDELETE)之后,这些操作可能来自表单提交、客户端发起的 API 调用或 SvelteKit 表单 action 内部。
  • 好处: 无需完整页面刷新即可实现高度动态和响应式的用户界面,显著提升用户体验。
  • invalidateAll() SvelteKit 还提供了 invalidateAll(),它会重新运行当前页面上所有 活动的 load 函数,无论它们是否有依赖关系。请使用 invalidate(key) 进行更精细的控制。
相关推荐
亮子AI3 天前
【Svelte,Vite】如何修改默认端口号 5173?
svelte
CF14年老兵1 个月前
我为什么放弃了 React(或许你也该试试)🔥
react.js·svelte·trae
Hilaku2 个月前
从 jQuery 到 React 再到 Svelte:我眼中的前端组件化演进史
前端·javascript·svelte
sHlsy19952 个月前
Svelte 5 完全指南:从入门到跨端应用开发
前端框架·svelte
天涯学馆2 个月前
为什么越来越多开发者偷偷用上了 Svelte?
前端·javascript·svelte
GuokLiu3 个月前
250708-Svelte项目从Debian迁移到无法联网的RHEL全流程指南
npm·svelte
heroboyluck4 个月前
Svelte 核心语法详解:Vue/React 开发者如何快速上手?
前端·svelte
hboot4 个月前
还不会Svelte?快来一起学习吧🤓
前端·svelte
姜 萌@cnblogs5 个月前
开源我的一款自用AI阅读器,引流Web前端、Rust、Tauri、AI应用开发
rust·web·tauri·svelte