找回密码
 立即注册
首页 业界区 安全 SvelteKit 最新中文文档教程(3)—— 数据加载 ...

SvelteKit 最新中文文档教程(3)—— 数据加载

羽桑 2025-6-1 20:51:08
前言

Svelte,一个语法简洁、入门容易,面向未来的前端框架。
从 Svelte 诞生之初,就备受开发者的喜爱,根据统计,从 2019 年到 2024 年,连续 6 年一直是开发者最感兴趣的前端框架 No.1
1.png

Svelte 以其独特的编译时优化机制著称,具有轻量级高性能易上手等特性,非常适合构建轻量级 Web 项目
为了帮助大家学习 Svelte,我同时搭建了 Svelte 最新的中文文档站点。
如果需要进阶学习,也可以入手我的小册《Svelte 开发指南》,语法篇、实战篇、原理篇三大篇章带你系统掌握 Svelte!
欢迎围观我的“网页版朋友圈”、加入“冴羽·成长陪伴社群”,踏上“前端大佬成长之路”。
数据加载

在渲染一个 +page.svelte 组件(及其包含的 +layout.svelte 组件)之前,我们通常需要获取一些数据。这是通过定义 load 函数来实现的。
页面数据

一个 +page.svelte 文件可以有一个同级的 +page.js 文件,该文件导出一个 load 函数,该函数的返回值可以通过 data 属性在页面中使用:
  1. /// file: src/routes/blog/[slug]/+page.js
  2. /** @type {import('./$types').PageLoad} */
  3. export function load({ params }) {
  4.         return {
  5.                 post: {
  6.                         title: `Title for ${params.slug} goes here`,
  7.                         content: `Content for ${params.slug} goes here`
  8.                 }
  9.         };
  10. }
复制代码
  1. <h1>{data.post.title}</h1>
  2. {@html data.post.content}
复制代码
[!LEGACY]
在 Svelte 4 中,您需要使用 export let data 代替
得益于生成的 $types 模块,我们获得了完整的类型安全性。
+page.js 文件中的 load 函数在服务端和浏览器上都会运行(除非与 export const ssr = false 结合使用,在这种情况下它将仅在浏览器中运行)。如果您的 load 函数应该始终在服务端上运行(例如,因为它使用了私有环境变量或访问数据库),那么它应该放在 +page.server.js 中。
一个更贴合实际的博客文章 load 函数示例,它只在服务端上运行并从数据库中获取数据。可能如下所示:
  1. /// file: src/routes/blog/[slug]/+page.server.js
  2. // @filename: ambient.d.ts
  3. declare module '$lib/server/database' {
  4.         export function getPost(slug: string): Promise<{ title: string, content: string }>
  5. }
  6. // @filename: index.js
  7. // ---cut---
  8. import * as db from '$lib/server/database';
  9. /** @type {import('./$types').PageServerLoad} */
  10. export async function load({ params }) {
  11.         return {
  12.                 post: await db.getPost(params.slug)
  13.         };
  14. }
复制代码
注意类型从 PageLoad 变为 PageServerLoad,因为服务端 load 函数可以访问额外的参数。要了解何时使用 +page.js 和何时使用 +page.server.js文档:高级路由 请参阅 Universal 与 server。
布局数据

您的 +layout.svelte 文件也可以通过 +layout.js 或 +layout.server.js 加载数据。
  1. /// file: src/routes/blog/[slug]/+layout.server.js
  2. // @filename: ambient.d.ts
  3. declare module '$lib/server/database' {
  4.         export function getPostSummaries(): Promise>
  5. }
  6. // @filename: index.js
  7. // ---cut---
  8. import * as db from '$lib/server/database';
  9. /** @type {import('./$types').LayoutServerLoad} */
  10. export async function load() {
  11.         return {
  12.                 posts: await db.getPostSummaries()
  13.         };
  14. }
复制代码
  1. <main>
  2.        
  3.         {@render children()}
  4. </main>
  5.         <h2>More posts</h2>
  6.         <ul>
  7.                 {#each data.posts as post}
  8.                         <li>
  9.                                
  10.                                         {post.title}
  11.                                
  12.                         </li>
  13.                 {/each}
  14.         </ul>
  15. </aside>
复制代码
布局 load 函数返回的数据对子 +layout.svelte 组件和 +page.svelte 组件以及它"所属"的布局都可用。
  1. /// file: src/routes/blog/[slug]/+page.svelte<h1>{data.post.title}</h1>
  2. {@html data.post.content}+++{#if next}        Next post: {next.title}
  3. {/if}+++
复制代码
[!NOTE] 如果多个 load 函数返回具有相同键的数据,最后一个会"胜出" —— 布局 load 返回 { a: 1, b: 2 } 而页面 load 返回 { b: 3, c: 4 } 的结果将是 { a: 1, b: 3, c: 4 }。
page.data

+page.svelte 组件及其上面的每个 +layout.svelte 组件都可以访问自己的数据以及其所有父组件的数据。
在某些情况下,我们可能需要相反的效果 - 父布局可能需要访问页面数据或来自子布局的数据。例如,根布局可能想要访问从 +page.js 或 +page.server.js 中的 load 函数返回的 title 属性。这可以通过 page.data 实现:
  1. <svelte:head>
  2.         <title>{page.data.title}</title>
  3. </svelte:head>
复制代码
page.data 的类型信息由 App.PageData 提供。
[!LEGACY] > $app/state 是在 SvelteKit 2.12 中添加的。如果您使用的是早期版本或使用 Svelte 4,请使用 $app/stores 代替。它提供了一个具有相同接口的 page store,您可以订阅它,例如 $page.data.title。
Universal vs server

正如我们所见,有两种类型的 load 函数:

  • +page.js 和 +layout.js 文件导出的在服务端和浏览器上都运行的通用 load 函数
  • +page.server.js 和 +layout.server.js 文件导出的只在服务端运行的服务端 load 函数
从概念上讲,它们是相同的东西,但有一些重要的区别需要注意。
何时运行哪个 load 函数?

服务端 load 函数总是在服务端上运行。
默认情况下,通用 load 函数在用户首次访问页面时在 SSR 期间在服务端上运行。然后它们会在水合过程中再次运行,复用来自 fetch 请求的任何响应。所有后续调用通用 load 函数都发生在浏览器中。您可以通过页面选项自定义该行为。如果您禁用了服务端渲染,您将获得一个 SPA,通用 load 函数始终在客户端运行。
如果一个路由同时包含通用和服务端 load 函数,服务端 load 函数会先运行。
除非您预渲染页面 - 在这种情况下,它会在构建时被调用,否则 load 函数会在运行时被调用。
输入

通用和服务端 load 函数都可以访问描述请求的属性(params、route 和 url)以及各种函数(fetch、setHeaders、parent、depends 和 untrack)。这些在后面的章节中会描述。
服务端 load 函数使用 ServerLoadEvent 调用,它从 RequestEvent 继承 clientAddress、cookies、locals、platform 和 request。
通用 load 函数使用具有 data 属性的 LoadEvent 调用。如果您在 +page.js 和 +page.server.js(或 +layout.js 和 +layout.server.js)中都有 load 函数,则服务端 load 函数的返回值是通用 load 函数参数的 data 属性。
输出

通用 load 函数可以返回包含任何值的对象,包括自定义类和组件构造函数等内容。
服务端 load 函数必须返回可以用 devalue 序列化的数据 - 任何可以用 JSON 表示的内容,以及像 BigInt、Date、Map、Set 和 RegExp 这样的内容,或重复/循环引用 - 这样它才能通过网络传输。您的数据可以包含promises,在这种情况下它将被流式传输到浏览器。
何时使用哪个

当您需要直接访问数据库或文件系统,或需要使用私有环境变量时,服务端 load 函数很方便。
当您需要从外部 API fetch 数据且不需要私有凭据时,通用 load 函数很有用,因为 SvelteKit 可以直接从 API 获取数据而无需通过服务端。当您需要返回无法序列化的内容(如 Svelte 组件构造函数)时,它们也很有用。
在极少数情况下,您可能需要同时使用两者 - 例如,您可能需要返回一个使用服务端数据初始化的自定义类的实例。当同时使用两者时,服务端 load 的返回值不会直接传递给页面,而是传递给通用 load 函数(作为 data 属性):
  1. /// file: src/routes/+page.server.js
  2. /** @type {import('./$types').PageServerLoad} */
  3. export async function load() {
  4.         return {
  5.                 serverMessage: 'hello from server load function'
  6.         };
  7. }
复制代码
  1. /// file: src/routes/+page.js
  2. // @errors: 18047
  3. /** @type {import('./$types').PageLoad} */
  4. export async function load({ data }) {
  5.         return {
  6.                 serverMessage: data.serverMessage,
  7.                 universalMessage: 'hello from universal load function'
  8.         };
  9. }
复制代码
使用 URL 数据

通常 load 函数以某种方式依赖于 URL。为此,load 函数提供了 url、route 和 params。
url

URL 的一个实例,包含诸如 origin、hostname、pathname 和 searchParams(包含解析后的查询字符串,作为 URLSearchParams 对象)等属性。在 load 期间无法访问 url.hash,因为它在服务端上不可用。
[!NOTE] 在某些环境中,这是在服务端渲染期间从请求头派生的。例如,如果您使用 adapter-node,您可能需要配置适配器以使 URL 正确。
route

包含当前路由目录相对于 src/routes 的名称:
  1. /// file: src/routes/a/[b]/[...c]/+page.js
  2. /** @type {import('./$types').PageLoad} */
  3. export function load({ route }) {
  4.         console.log(route.id); // '/a/[b]/[...c]'
  5. }
复制代码
params

params 是从 url.pathname 和 route.id 派生的。
给定一个 route.id 为 /a//[...c] 且 url.pathname 为 /a/x/y/z 时,params 对象将如下所示:
  1. {
  2.         "b": "x",
  3.         "c": "y/z"
  4. }
复制代码
发起 fetch 请求

要从外部 API 或 +server.js 处理程序获取数据,您可以使用提供的 fetch 函数,它的行为与原生 fetch web API完全相同,但有一些额外的功能:

  • 它可以在服务端上发起带凭据的请求,因为它继承了页面请求的 cookie 和 authorization 标头。
  • 它可以在服务端上发起相对请求(通常,当在服务端上下文中使用时,fetch 需要带有源的 URL)。
  • 内部请求(例如对 +server.js 路由的请求)在服务端上运行时直接转到处理函数,无需 HTTP 调用的开销。
  • 在服务端渲染期间,通过钩入 text、json 和 arrayBuffer 方法来捕获响应并将其内联到渲染的 HTML 中 Response 对象。请注意,除非通过 filterSerializedResponseHeaders 显式包含,否则标头将不会被序列化。
  • 在水合过程中,响应将从 HTML 中读取,确保一致性并防止额外的网络请求 - 如果在使用浏览器 fetch 而不是 loadfetch 时,在浏览器控制台中收到警告,这就是原因。
  1. /// file: src/routes/items/[id]/+page.js
  2. /** @type {import('./$types').PageLoad} */
  3. export async function load({ fetch, params }) {
  4.         const res = await fetch(`/api/items/${params.id}`);
  5.         const item = await res.json();
  6.         return { item };
  7. }
复制代码
Cookies

服务端 load 函数可以获取和设置cookies。
  1. /// file: src/routes/+layout.server.js
  2. // @filename: ambient.d.ts
  3. declare module '$lib/server/database' {
  4.   export function getUser(sessionid: string | undefined): Promise<{ name: string, avatar: string }>
  5. }
  6. // @filename: index.js
  7. // ---cut---
  8. import * as db from '$lib/server/database';
  9. /** @type {import('./$types').LayoutServerLoad} */
  10. export async function load({ cookies }) {
  11.   const sessionid = cookies.get('sessionid');
  12.   return {
  13.     user: await db.getUser(sessionid)
  14.   };
  15. }
复制代码
只有当目标主机与 SvelteKit 应用程序相同或是其更具体的子域名时,Cookie 才会通过提供的 fetch 函数传递。
例如,如果 SvelteKit 正在为 my.domain.com 提供服务:

  • domain.com 将不会接收 cookies
  • my.domain.com 将会接收 cookies
  • api.domain.com 将不会接收 cookies
  • sub.my.domain.com 将会接收 cookies
当设置 credentials: 'include' 时,其他 cookies 将不会被传递,因为 SvelteKit 无法知道哪个 cookie 属于哪个域(浏览器不会传递这些信息),所以转发任何 cookie 都是不安全的。使用 handleFetch hook 钩子来解决这个问题。
Headers

服务端和通用 load 函数都可以访问 setHeaders 函数,当在服务端上运行时,可以为响应设置头部信息。(在浏览器中运行时,setHeaders 不会产生效果。)这在你想要缓存页面时很有用,例如:
  1. // @errors: 2322 1360
  2. /// file: src/routes/products/+page.js
  3. /** @type {import('./$types').PageLoad} */
  4. export async function load({ fetch, setHeaders }) {
  5.         const url = `https://cms.example.com/products.json`;
  6.         const response = await fetch(url);
  7.         // Headers are only set during SSR, caching the page's HTML
  8.         // for the same length of time as the underlying data.
  9.         setHeaders({
  10.                 age: response.headers.get('age'),
  11.                 'cache-control': response.headers.get('cache-control')
  12.         });
  13.         return response.json();
  14. }
复制代码
多次设置相同的标头(即使在不同的 load 函数中)是一个错误。使用 setHeaders 函数时,每个标头只能设置一次。你不能使用 setHeaders 添加 set-cookie 标头 — 应该使用cookies.set(name, value, options) 代替。
使用父级数据

有时候让 load 函数访问父级 load 函数中的数据是很有用的,这可以通过 await parent() 实现:
  1. /// file: src/routes/+layout.js
  2. /** @type {import('./$types').LayoutLoad} */
  3. export function load() {
  4.         return { a: 1 };
  5. }
复制代码
  1. /// file: src/routes/abc/+layout.js
  2. /** @type {import('./$types').LayoutLoad} */
  3. export async function load({ parent }) {
  4.         const { a } = await parent();
  5.         return { b: a + 1 };
  6. }
复制代码
  1. /// file: src/routes/abc/+page.js
  2. /** @type {import('./$types').PageLoad} */
  3. export async function load({ parent }) {
  4.         const { a, b } = await parent();
  5.         return { c: a + b };
  6. }
复制代码
  1. <p>{data.a} + {data.b} = {data.c}</p>
复制代码
[!NOTE] 注意,+page.js 中的 load 函数接收来自两个布局 load 函数的合并数据,而不仅仅是直接父级的数据。
在 +page.server.js 和 +layout.server.js 内部,parent 从父级 +layout.server.js 文件返回数据。
在 +page.js 或 +layout.js 中,它将返回父级+layout.js 文件中的数据。然而,缺失的 +layout.js 会被视为 ({ data }) => data 函数,这意味着它也会返回未被 +layout.js 文件"遮蔽"的父级 +layout.server.js 文件中的数据。
使用 await parent() 时要注意避免瀑布流。例如,getData(params) 并不依赖于调用 parent() 的结果,所以我们应该先调用它以避免延迟渲染。
  1. /// file: +page.js
  2. // @filename: ambient.d.ts
  3. declare function getData(params: Record<string, string>): Promise<{ meta: any }>
  4. // @filename: index.js
  5. // ---cut---
  6. /** @type {import('./$types').PageLoad} */
  7. export async function load({ params, parent }) {
  8.   ---const parentData = await parent();---
  9.   const data = await getData(params);
  10.   +++const parentData = await parent();+++
  11.   return {
  12.     ...data,
  13.     meta: { ...parentData.meta, ...data.meta }
  14.   };
  15. }
复制代码
Errors

如果在 load 期间抛出错误,将渲染最近的 +error.svelte。对于预期的错误,使用来自 @sveltejs/kit 的 error 辅助函数来指定 HTTP 状态码和可选消息:
  1. /// file: src/routes/admin/+layout.server.js
  2. // @filename: ambient.d.ts
  3. declare namespace App {
  4.   interface Locals {
  5.     user?: {
  6.       name: string;
  7.       isAdmin: boolean;
  8.     }
  9.   }
  10. }
  11. // @filename: index.js
  12. // ---cut---
  13. import { error } from '@sveltejs/kit';
  14. /** @type {import('./$types').LayoutServerLoad} */
  15. export function load({ locals }) {
  16.   if (!locals.user) {
  17.     error(401, 'not logged in');
  18.   }
  19.   if (!locals.user.isAdmin) {
  20.     error(403, 'not an admin');
  21.   }
  22. }
复制代码
调用 error(...) 将抛出一个异常,这使得在辅助函数内部停止执行变得容易。
如果抛出了一个意外错误,SvelteKit 将调用 handleError 并将其视为 500 内部错误。
[!NOTE] 在 SvelteKit 1.x 中,你必须自己 throw 错误
Redirects

要重定向用户,请使用来自 @sveltejs/kit 的 redirect 辅助函数,以指定用户应被重定向到的位置以及一个 3xx 状态码。与 error(...) 类似,调用 redirect(...) 将抛出一个异常,这使得在辅助函数内部停止执行变得容易。
  1. /// file: src/routes/user/+layout.server.js
  2. // @filename: ambient.d.ts
  3. declare namespace App {
  4.   interface Locals {
  5.     user?: {
  6.       name: string;
  7.     }
  8.   }
  9. }
  10. // @filename: index.js
  11. // ---cut---
  12. import { redirect } from '@sveltejs/kit';
  13. /** @type {import('./$types').LayoutServerLoad} */
  14. export function load({ locals }) {
  15.   if (!locals.user) {
  16.     redirect(307, '/login');
  17.   }
  18. }
复制代码
[!NOTE] 不要在 try {...} 块内使用 redirect(),因为重定向会立即触发 catch 语句。
在浏览器中,你也可以在 load 函数之外使用来自 $app.navigation 的 goto 通过编程的方式进行导航。
[!NOTE] 在 SvelteKit 1.x 中,你必须自己 throw 这个 redirect
Streaming with promises

当使用服务端 load 时,Promise 将在 resolve 时流式传输到浏览器。如果你有较慢的、非必要的数据,这很有用,因为你可以在所有数据可用之前开始渲染页面:
  1. /// file: src/routes/blog/[slug]/+page.server.js
  2. // @filename: ambient.d.ts
  3. declare global {
  4.   const loadPost: (slug: string) => Promise<{ title: string, content: string }>;
  5.   const loadComments: (slug: string) => Promise<{ content: string }>;
  6. }
  7. export {};
  8. // @filename: index.js
  9. // ---cut---
  10. /** @type {import('./$types').PageServerLoad} */
  11. export async function load({ params }) {
  12.   return {
  13.     // make sure the `await` happens at the end, otherwise we
  14.     // can't start loading comments until we've loaded the post
  15.     comments: loadComments(params.slug),
  16.     post: await loadPost(params.slug)
  17.   };
  18. }
复制代码
这对创建骨架加载状态很有用,例如:
  1. <h1>{data.post.title}</h1>
  2. {@html data.post.content}{#await data.comments}  Loading comments...{:then comments}  {#each comments as comment}    {comment.content}
  3.   {/each}{:catch error}  error loading comments: {error.message}
  4. {/await}
复制代码
在流式传输数据时,请注意正确处理 Promise rejections。具体来说,如果懒加载的 Promise 在渲染开始前失败(此时会被捕获)且没有以某种方式处理错误,服务器可能会因 "unhandled promise rejection" 错误而崩溃。
当在 load 函数中直接使用 SvelteKit 的 fetch 时,SvelteKit 会为您处理这种情况。对于其他 Promise,只需为 Promise 添加一个空的 catch 即可将其标记为已处理。
  1. /// file: src/routes/+page.server.js
  2. /** @type {import('./$types').PageServerLoad} */
  3. export function load({ fetch }) {
  4.         const ok_manual = Promise.reject();
  5.         ok_manual.catch(() => {});
  6.         return {
  7.                 ok_manual,
  8.                 ok_fetch: fetch('/fetch/that/could/fail'),
  9.                 dangerous_unhandled: Promise.reject()
  10.         };
  11. }
复制代码
[!NOTE] 在不支持流式传输的平台上(如 AWS Lambda 或 Firebase),响应将被缓冲。这意味着页面只会在所有 promise resolve 后才会渲染。如果您使用代理(例如 NGINX),请确保它不会缓冲来自代理服务器的响应。
[!NOTE] 流式数据传输只有在启用 JavaScript 时才能工作。如果页面是服务端渲染的,您应该避免从通用 load 函数返回 promise,因为这些 promise 不会被流式传输 —— 相反,当函数在浏览器中重新运行时,promise 会被重新创建。
[!NOTE] 一旦响应开始流式传输,就无法更改响应的标头和状态码,因此您无法 setHeaders 或抛出重定向到流式 promise 内。
[!NOTE] 在 SvelteKit 1.x 中,顶层 promise 会自动 awaited,只有嵌套的 promise 才会流式传输。
并行加载

在渲染(或导航到)页面时,SvelteKit 会同时运行所有 load 函数,避免请求瀑布。在客户端导航期间,多个服务器 load 函数的调用结果会被组合到单个响应中。一旦所有 load 函数都返回结果,页面就会被渲染。
重新运行 load 函数

SvelteKit 会追踪每个 load 函数的依赖关系,以避免在导航过程中不必要的重新运行。
例如,给定一对这样的 load 函数...
  1. /// file: src/routes/blog/[slug]/+page.server.js
  2. // @filename: ambient.d.ts
  3. declare module '$lib/server/database' {
  4.   export function getPost(slug: string): Promise<{ title: string, content: string }>
  5. }
  6. // @filename: index.js
  7. // ---cut---
  8. import * as db from '$lib/server/database';
  9. /** @type {import('./$types').PageServerLoad} */
  10. export async function load({ params }) {
  11.   return {
  12.     post: await db.getPost(params.slug)
  13.   };
  14. }
复制代码
  1. /// file: src/routes/blog/[slug]/+layout.server.js
  2. // @filename: ambient.d.ts
  3. declare module '$lib/server/database' {
  4.   export function getPostSummaries(): Promise>
  5. }
  6. // @filename: index.js
  7. // ---cut---
  8. import * as db from '$lib/server/database';
  9. /** @type {import('./$types').LayoutServerLoad} */
  10. export async function load() {
  11.   return {
  12.     posts: await db.getPostSummaries()
  13.   };
  14. }
复制代码
...其中 +page.server.js 中的函数在从 /blog/trying-the-raw-meat-diet 导航到 /blog/i-regret-my-choices 时会重新运行,因为 params.slug 发生了变化。而 +layout.server.js 中的函数则不会重新运行,因为数据仍然有效。换句话说,我们不会第二次调用 db.getPostSummaries()。
如果父级 load 函数重新运行,调用了 await parent() 的 load 函数也会重新运行。
依赖追踪在 load 函数返回后不再适用 — 例如,在嵌套的 promise 中访问 params.x 不会在 params.x 改变时导致函数重新运行。(别担心,如果你不小心这样做了,在开发环境中会收到警告。)相反,应该在 load 函数的主体中访问参数。
搜索参数的追踪独立于 URL 的其余部分。例如,在 load 函数中访问 event.url.searchParams.get("x") 将使该 load 函数在从 ?x=1 导航到 ?x=2 时重新运行,但从 ?x=1&y=1 导航到 ?x=1&y=2 时则不会重新运行。
取消依赖追踪

在极少数情况下,你可能希望将某些内容排除在依赖追踪机制之外。你可以使用提供的 untrack 函数实现这一点:
  1. /// file: src/routes/+page.js
  2. /** @type {import('./$types').PageLoad} */
  3. export async function load({ untrack, url }) {
  4.         // Untrack url.pathname so that path changes don't trigger a rerun
  5.         if (untrack(() => url.pathname === '/')) {
  6.                 return { message: 'Welcome!' };
  7.         }
  8. }
复制代码
手动失效

你还可以使用 invalidate(url) 重新运行适用于当前页面的 load 函数,它会重新运行所有依赖于 url 的 load 函数,以及使用 invalidateAll() 重新运行每个 load 函数。服务端加载函数永远不会自动依赖于获取数据的 url,以避免将秘密泄露给客户端。
如果一个 load 函数调用了 fetch(url) 或 depends(url),那么它就依赖于 url。注意,url 可以是以 [a-z]开头的自定义标识符:
  1. /// file: src/routes/random-number/+page.js
  2. /** @type {import('./$types').PageLoad} */
  3. export async function load({ fetch, depends }) {
  4.         // load reruns when `invalidate('https://api.example.com/random-number')` is called...
  5.         const response = await fetch('https://api.example.com/random-number');
  6.         // ...or when `invalidate('app:random')` is called
  7.         depends('app:random');
  8.         return {
  9.                 number: await response.json()
  10.         };
  11. }
复制代码
  1. <p>random number: {data.number}</p>
  2. <button onclick={rerunLoadFunction}>Update random number</button>
复制代码
load 函数何时重新运行?

总的来说,load 函数在以下情况下会重新运行:

  • 它引用了 params 中已更改值的属性
  • 它引用了 url 的某个属性(如 url.pathname 或url.search)且该属性的值已更改。request.url 中的属性不会被追踪
  • 它调用 url.searchParams.get(...)、url.searchParams.getAll(...) 或 url.searchParams.has(...),且相关参数发生变化。访问 url.searchParams 的其他属性与访问 url.search具有相同的效果。
  • 它调用 await parent() 且父 load 函数重新运行
  • 当子 load 函数调用 await parent() 并重新运行,且父函数是服务端 load 函数
  • 它通过 fetch(仅限通用 load)或 depends 声明了对特定 URL 的依赖,且该 URL 被 invalidate(url) 标记为无效
  • 所有活动的 load 函数都被 invalidateAll() 强制重新运行
params 和 url 可以在响应  链接点击、 交互goto 调用或 重定向 时发生变化。
注意,重新运行 load 函数将更新相应 +layout.svelte 或 +page.svelte 中的 data 属性;这不会导致组件重新创建。因此,内部状态会被保留。如果这不是你想要的,你可以在afterNavigate 回调中重置所需内容,或者用 {#key ...} 块包装你的组件。
对身份验证的影响

数据加载的几个特性对身份验证有重要影响:

  • 布局 load 函数不会在每个请求时运行,例如在子路由之间的客户端导航期间。(load函数何时重新运行?)
  • 布局和页面 load 函数会同时运行,除非调用了 await parent()。如果布局 load 抛出错误,页面 load 函数会运行,但客户端将不会收到返回的数据。
有几种可能的策略来确保在受保护代码之前进行身份验证检查。
为防止数据瀑布并保留布局 load 缓存:

  • 使用 hooks 在任何 load 函数运行之前保护多个路由
  • 在 +page.server.js load 函数中直接使用身份验证守卫进行特定路由保护
在 +layout.server.js 中放置身份验证守卫要求所有子页面在受保护代码之前调用 await parent()。除非每个子页面都依赖于await parent() 返回的数据,否则其他选项会更有性能优势。
拓展阅读


  • 教程:数据加载
  • 教程:错误和重定向
  • 教程:高级加载
Svelte 中文文档

点击查看中文文档 - SvelteKit 数据加载。
系统学习 Svelte,欢迎入手小册《Svelte 开发指南》。语法篇、实战篇、原理篇三大篇章带你系统掌握 Svelte!
此外我还写过 JavaScript 系列、TypeScript 系列、React 系列、Next.js 系列、冴羽答读者问等 14 个系列文章, 全系列文章目录:https://github.com/mqyqingfeng/Blog
欢迎围观我的“网页版朋友圈”、加入“冴羽·成长陪伴社群”,踏上“前端大佬成长之路”。

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册