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

Next.js 13.4 App Router中error.tsx的reset()方法失效问题

Next.js 13.4 App Router:error.tsx的reset()无法重新触发Server Component的fetch请求

问题描述

使用Next.js 13.4 App Router,在Server Component中通过fetch从json-server获取数据。当json-server宕机时,error.tsx页面正常显示并带有“Try again”按钮,但启动服务器后点击该按钮调用reset()方法,页面并未重新加载,fetch也未正常执行。

原因分析

  1. Server Component缓存机制:即使fetch设置了next: { revalidate: 0 },在错误状态下,Next.js可能仍保留之前的错误状态,导致reset()调用后未重新触发服务器端的fetch请求。
  2. reset()的局限性:reset()主要用于尝试重新渲染当前路由段,但对于Server Component的服务器端逻辑,单纯调用reset()无法强制重新执行fetch请求,需结合路由刷新触发服务器端重新渲染。

解决方案

方案1:结合router.refresh()强制刷新路由

在error.tsx中,调用reset()后通过router.refresh()强制刷新整个路由,触发Server Component重新执行fetch请求:

修改后的error.tsx代码:

"use client"; // Error components must be Client Components

import Link from "next/link";
import { useEffect } from "react";
import { useRouter } from "next/navigation"; // 导入useRouter

export default function Error({
  error,
  reset,
}: {
  error: Error & { digest?: string };
  reset: () => void;
}) {
  const router = useRouter(); // 获取router实例

  useEffect(() => {
    console.error(error);
  }, [error]);

  return (
    <div className="flex flex-col justify-center items-center m-auto pt-16 ">
      <h2>Something went wrong!</h2>
      <p className="text-red-500 text-sm mt-3">
        Error Message :: {error.message}
      </p>
      <div className="flex gap-4">
        <button
          className="rounded-md py-2 px-4 mt-6 bg-yellow-500 text-white"
          onClick={() => {
            reset();
            router.refresh(); // 强制刷新路由
          }}
        >
          Try again
        </button>
        <Link
          href="/"
          className="rounded-md py-2 px-4 mt-6 bg-green-600 text-white"
        >
          Go Home
        </Link>
      </div>
    </div>
  );
}

方案2:明确禁用fetch缓存

在Server Component的fetch请求中添加cache: 'no-store',确保每次请求都从服务器获取最新数据,避免错误状态被缓存:

修改后的TicketList组件中getTickets函数:

const getTickets = async () => {
  const response = await fetch("http://localhost:4000/tickets", {
    cache: 'no-store', // 明确禁用缓存
  });
  
  // 可选:添加错误处理,确保请求失败时抛出错误
  if (!response.ok) {
    throw new Error(`请求失败:${response.status}`);
  }

  return response.json();
};

方案3:添加错误边界的重试逻辑(可选)

在Server Component中添加错误捕获,结合Suspense组件,确保错误状态能被正确重置:

修改后的TicketList组件:

import { Ticket } from "@/models/ticket";
import Link from "next/link";
import React, { Suspense } from "react";
import TicketCard from "./ticketCard";

const getTickets = async () => {
  const response = await fetch("http://localhost:4000/tickets", {
    cache: 'no-store',
  });

  if (!response.ok) {
    throw new Error(`请求失败:${response.status}`);
  }

  return response.json();
};

async function TicketsContent() {
  const tickets: Ticket[] = await getTickets();

  return (
    <section className="flex flex-col">
      {tickets.map((ticket: any) => <TicketCard ticket={ticket} key={ticket.id} />).reverse()}
      {tickets.length === 0 && (
        <p className="text-center text-2xl font-bold">No Tickets Yet!</p>
      )}
    </section>
  );
}

export default function TicketList() {
  return (
    <Suspense fallback={<div>加载中...</div>}>
      <TicketsContent />
    </Suspense>
  );
}

说明

  • 方案1是最直接的解决方式,通过router.refresh()强制触发服务器端的重新渲染,确保fetch请求被重新执行。
  • 方案2和3是辅助优化,确保缓存不会影响请求结果,同时完善错误处理逻辑,让error.tsx能更准确地捕获和处理错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 17:04:55