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

在NextJS 13中使用TanStack Query实现图片数据即时更新

解决NextJS 13 + TanStack Query图片数据即时更新问题

一、图片删除功能修复

1. 同步更新分类查询数据

当前删除操作仅更新了全局图片列表的查询["images"],但用户若处于分类视图(selectedCategory !== "all"),分类对应的查询["images", selectedCategory]未同步更新,导致界面无变化。需在onMutate中同时处理分类数据:

onMutate: async (url: string | null | undefined) => {
  // 取消全局和当前分类的查询请求
  await queryClient.cancelQueries({ queryKey: ["images"] });
  if (selectedCategory && selectedCategory !== "all") {
    await queryClient.cancelQueries({ queryKey: ["images", selectedCategory] });
  }

  // 保存原始数据用于回滚
  const previousImages = queryClient.getQueryData(["images"]);
  const previousCategoryImages = selectedCategory && selectedCategory !== "all" 
    ? queryClient.getQueryData(["images", selectedCategory]) 
    : null;

  // 更新全局图片列表
  queryClient.setQueryData(
    ["images"],
    (old: string[] | undefined) => old?.filter((image) => image !== url) ?? []
  );

  // 更新当前分类的图片列表
  if (selectedCategory && selectedCategory !== "all") {
    queryClient.setQueryData(
      ["images", selectedCategory],
      (old: string[] | undefined) => old?.filter((image) => image !== url) ?? []
    );
  }

  return { previousImages, previousCategoryImages };
},

2. 错误回滚时恢复分类数据

在onError中同时回滚全局和分类的原始数据:

onError: (error, _, context) => {
  console.error("Error deleting the image:", error);
  toast.error(`${error}`, { toastId });
  
  // 回滚全局数据
  if (context?.previousImages) {
    queryClient.setQueryData(["images"], context.previousImages);
  }
  // 回滚分类数据
  if (context?.previousCategoryImages && selectedCategory && selectedCategory !== "all") {
    queryClient.setQueryData(["images", selectedCategory], context.previousCategoryImages);
  }
},

二、图片上传功能修复

1. 修正数据类型不匹配问题

当前上传的onMutate直接将FormData加入URL数组,与后端返回的string[]格式冲突,导致乐观更新无效。需先从后端获取真实URL:

首先修改mutationFn,返回后端返回的新图片URL:

mutationFn: async (formData: FormData) => {
  const response = await fetch(`${process.env.BACKEND_URL}/upload`, {
    method: "POST",
    body: formData,
    headers: {
      authorization: `Bearer ${session?.user.accessToken}`,
    },
  });

  const data = await response.json();

  if (!response.ok) {
    throw new Error(data.message || "Upload failed");
  }
  // 假设后端返回的data是图片URL字符串,根据实际格式调整
  return data;
},

2. 正确更新查询数据

在onSuccess中用后端返回的真实URL更新全局和分类查询:

onSuccess: async (newImageUrl) => {
  // 更新全局图片列表
  queryClient.setQueryData(["images"], (old: string[] | undefined) => 
    old ? [...old, newImageUrl] : [newImageUrl]
  );
  // 更新对应分类的图片列表
  if (selectedCategory) {
    queryClient.setQueryData(["images", selectedCategory], (old: string[] | undefined) => 
      old ? [...old, newImageUrl] : [newImageUrl]
    );
  }
  // 或直接失效查询,重新获取最新数据
  await queryClient.invalidateQueries({ queryKey: ["images"] });
  if (selectedCategory) {
    await queryClient.invalidateQueries({ queryKey: ["images", selectedCategory] });
  }
  toast.success("Image uploaded successfully", { toastId });
},

3. 修正提示逻辑

将成功/错误提示移到对应钩子,避免错误场景显示成功提示:

onError: (error) => {
  console.error("Upload error:", error);
  toast.error(`${error.message}`, { toastId });
},
onSettled: () => {
  setSelectedFile(null);
  setImageTitle("");
  setSelectedCategory("");
},

三、其他优化

1. 移除无用的useEffect

ImagesPage中以下useEffect是多余的,useQuery会自动根据selectedCategory变化重新请求,直接删除:

// 移除该代码块
useEffect(() => {
  if (selectedCategory) {
    handleImagesByCategory({ category: selectedCategory, session });
  }
}, [selectedCategory]);

2. 处理undefined数据

在setQueryData时处理old为undefined的情况,避免报错:

// 示例:删除时的全局数据更新
queryClient.setQueryData(
  ["images"],
  (old: string[] | undefined) => old ? old.filter((image) => image !== url) : []
);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 22:14:57