You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Svelte+TanStack Query:避免重复API调用及缓存取文章问题求助

问题解决方案

技术栈

  • Svelte
  • @tanstack/svelte-query

项目背景

现有两个页面:

  1. posts/+page.svelte(文章列表页)
  2. post/[id]/[title]/+page.svelte(文章详情页)

基于Svelte开发,使用TanStack Query存储API数据,参考React文档(语法多数兼容)。


核心问题及修复方案

问题1:文章列表页重复触发API请求

每次导航到posts页面都会重新调用API,产生冗余请求。

修复思路

TanStack Query的缓存需要全局共享的QueryClient实例才能生效,同时通过配置缓存策略控制数据新鲜度,避免不必要的重新请求。

具体步骤

  1. 创建全局共享的QueryClient实例
    在$lib/posts/queryClient.ts中定义全局QueryClient:
import { QueryClient } from '@tanstack/svelte-query';

export const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      staleTime: 3600000, // 1小时内数据视为"新鲜",不触发重新请求
      cacheTime: 86400000, // 缓存保留24小时
      refetchOnMount: false, // 组件挂载时不主动重新请求
      refetchOnWindowFocus: false, // 窗口聚焦时不重新请求
    },
  },
});
  1. 在根布局中注入QueryClient
    修改+layout.svelte,让所有页面共享同一个QueryClient:
<script>
  import { QueryClientProvider } from '@tanstack/svelte-query';
  import { queryClient } from '$lib/posts/queryClient';
</script>

<QueryClientProvider client={queryClient}>
  <slot />
</QueryClientProvider>
  1. 简化列表页代码
    去掉不必要的store同步,直接使用Query的响应式数据:
<script lang="ts">
  import { createQuery } from "@tanstack/svelte-query";
  import type { Post } from "$lib/models/Post";
  import { fetchPaginatedPosts } from "$lib/posts/fetch-pagination";

  const query = createQuery({
    queryKey: ["posts"],
    queryFn: fetchPaginatedPosts,
  });

  let posts: Post[] = [];

  $: if ($query.data?.posts) {
    posts = $query.data.posts;
  }
</script>

配置完成后,只要缓存数据在新鲜期内,导航回列表页就不会触发新的API请求。


问题2:详情页从缓存获取文章返回undefined

尝试从缓存获取单篇文章失败,返回undefined。

问题根源

  • 创建了新的QueryCache实例,无法访问全局QueryClient的缓存
  • find方法的语法错误(未传入回调函数)
  • 依赖onMount而非响应式语句监听id变化

修复后的详情页代码

<script lang="ts">
  import { page } from "$app/stores";
  import type { Post } from "$lib/models/Post";
  import { queryClient } from "$lib/posts/queryClient"; // 引入全局QueryClient

  let post: Post | undefined;

  // 响应式监听id变化,实时从缓存获取对应文章
  $: {
    const id = $page.params.id;
    const cachedData = queryClient.getQueryData(["posts"]);
    if (cachedData?.posts) {
      post = cachedData.posts.find(item => item.id === id);
      console.log(post);
    }
  }
</script>

关于你尝试的hooks.server.ts补充

如果需要在服务端预加载数据并填充缓存,可保留该代码,但注意:

  • 服务端每次请求会创建新的QueryClient实例,缓存仅对当前请求有效
  • 无需额外维护fetchedPosts store,直接通过全局QueryClient的缓存即可实现数据共享

内容的提问来源于stack exchange,提问作者kawa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 22:42:12