Next.js中useSWR调用toISOString引发无限API请求问题咨询
问题根因
useSWR 会以传入的第一个参数作为请求缓存的唯一key,只要key发生变化,就会自动触发新的请求。你当前的代码在每次组件渲染时,都会重新创建Date实例并调用toISOString(),哪怕两次渲染只间隔几毫秒,生成的ISO字符串末尾的毫秒数也会不同,导致请求key持续变化。新请求返回后又会触发组件重渲染,进而生成新的key,就形成了无限请求的死循环。
解决方案
你只需要把生成的日期字符串缓存起来,避免每次渲染都生成新值即可,最常用的方式是用useMemo包裹日期生成逻辑:
首先修改导入语句,引入useMemo:
import { useRouter } from "next/router"; import { useMemo } from "react"; // 新增导入
然后把原来的日期生成逻辑替换为useMemo包裹的版本,依赖项设为空数组,保证只会在组件首次渲染时计算一次:
const UserData = () => { const router = useRouter(); const { id } = router.query; // 用useMemo缓存日期值,仅首次渲染计算一次 const ssd = useMemo(() => { const today = new Date(); const yesterday = new Date(today); yesterday.setDate(yesterday.getDate() - 1); return yesterday.toISOString(); }, []); const result = useSWR(`/api/user/${id}/${ssd}`, fetcher, { revalidateOnFocus: false }); // 其余逻辑保持不变 }
如果你的业务场景需要在特定条件下更新日期(比如页面停留超过零点时刷新日期),只需要把对应的触发条件加入useMemo的依赖数组即可。如果只需要精确到天的日期,也可以把toISOString()返回的结果切掉时间部分,避免毫秒级差异带来的key变化:
return yesterday.toISOString().slice(0, 10); // 仅返回YYYY-MM-DD格式
如果router.query.id是异步加载的(比如页面首次渲染时还没拿到路由参数),可以给useSWR的key加判断,避免发起无效请求:
const result = useSWR(id ? `/api/user/${id}/${ssd}` : null, fetcher, { revalidateOnFocus: false });
内容的提问来源于stack exchange,提问作者w. Patrick Gale
相关产品推荐
相关产品推荐

