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

Next.js 13:如何正确重定向到动态路由避免显示过期数据?

问题

使用Next.js开发时,通过自定义Hook里的router.replace()/router.push()实现按钮点击重定向,目标页面显示过期数据,仅window.location.href能解决。已尝试设置dynamic: force-dynamic和fetch的cache: "no-store"但无效。

相关代码

自定义重定向Hook

import { useRouter } from "next/navigation";

export function useDynamicRedirect(statusId: number, itemId: number) {
  const router = useRouter();

  const statusIdRedirectMap = {
    1: `/pathA/${itemId}`,
    2: `/pathB/${itemId}`,
    10: `/pathA/${itemId}`, // Some special case
  };

  const redirectPath = statusIdRedirectMap[statusId as keyof typeof statusIdRedirectMap];

  return () => {
    if (redirectPath) {
      router.replace(redirectPath, {
        scroll: false,
      });

      console.log(`Redirecting to ${redirectPath}`);

      // Temporary solution:
      // window.location.href = redirectPath;
    } else {
      console.warn(`No redirect path defined for statusId ${statusId}`);
    }
  };
}

表格组件中使用Hook

<Table.Body className="divide-y">
  {data.map((item) => {
    const redirect = useDynamicRedirect(item.Status, item.Id);

    return (
      <Table.Row
        key={item.Id}
        className="bg-white dark:border-gray-700 dark:bg-gray-800"
      >
        <Table.Cell></Table.Cell>
        {Object.entries(item).map(([key, value], index) => (
          <Table.Cell className="w-full truncate p-3" key={index}>
            {key === "Status"
              ? getStatusDetails(value as number)
              : (value as string)}
          </Table.Cell>
        ))}

        <Table.Cell>
          <a
            className="cursor-pointer rounded-2xl bg-blue-500 p-2 font-medium text-white hover:bg-blue-600 dark:text-white"
            onClick={redirect}
          >
            View
          </a>
        </Table.Cell>
      </Table.Row>
    );
  })}
</Table.Body>

表格所在页面

import { DynamicTable } from "@/components/DynamicTable";
import { publicApiURL } from "@/constants/api";

export const dynamic = "force-dynamic";

export default async function DynamicPage() {
  const fetchData = async () => {
    const response = await fetch(`${publicApiURL}/Data/List`, {
      cache: "no-store",
    });
    return response.json();
  };

  const items = await fetchData();

  return <DynamicTable items={items} />;
}
原因分析
  1. 违反React Hook规则:在data.map循环内部调用useDynamicRedirect,Hook必须在组件顶层作用域调用,不能在循环、条件或嵌套函数中执行,这会导致Hook状态管理异常,引发路由行为不稳定。
  2. 目标页面缓存策略问题:dynamic: force-dynamic和cache: "no-store"仅作用于当前表格页面,目标页面(/pathA/[itemId]、/pathB/[itemId])可能仍使用默认缓存策略(如force-cache)。Next.js客户端导航(router.push/replace)会复用已缓存的目标页面组件和数据,不会重新发起请求获取最新数据;而window.location.href会触发全页面刷新,绕过客户端缓存重新请求资源。
解决方案

1. 修复Hook调用位置

将useDynamicRedirect逻辑从循环中移出,改为在按钮点击时动态计算路径,或封装成非Hook工具函数:

// 替换原自定义Hook为带参数的回调函数
import { useRouter } from "next/navigation";

export function useDynamicRedirect() {
  const router = useRouter();

  return (statusId: number, itemId: number) => {
    const statusIdRedirectMap = {
      1: `/pathA/${itemId}`,
      2: `/pathB/${itemId}`,
      10: `/pathA/${itemId}`,
    };

    const redirectPath = statusIdRedirectMap[statusId as keyof typeof statusIdRedirectMap];
    
    if (redirectPath) {
      router.replace(redirectPath, { scroll: false });
      console.log(`Redirecting to ${redirectPath}`);
    } else {
      console.warn(`No redirect path defined for statusId ${statusId}`);
    }
  };
}

在表格组件顶层调用Hook,循环中传入参数:

<Table.Body className="divide-y">
  {/* 在组件顶层调用Hook */}
  const handleRedirect = useDynamicRedirect();
  
  {data.map((item) => {
    return (
      <Table.Row key={item.Id} className="bg-white dark:border-gray-700 dark:bg-gray-800">
        {/* ... 其他单元格 ... */}
        <Table.Cell>
          <a
            className="cursor-pointer rounded-2xl bg-blue-500 p-2 font-medium text-white hover:bg-blue-600 dark:text-white"
            onClick={() => handleRedirect(item.Status, item.Id)}
          >
            View
          </a>
        </Table.Cell>
      </Table.Row>
    );
  })}
</Table.Body>

2. 配置目标页面的缓存策略

确保目标页面每次客户端导航都获取最新数据:

方式一:设置页面为动态渲染

在目标页面文件顶部添加:

export const dynamic = "force-dynamic";

方式二:在fetch请求中禁用缓存

目标页面的数据获取请求中设置cache: "no-store"或revalidate: 0:

export default async function PathAPage({ params }: { params: { itemId: string } }) {
  const response = await fetch(`${publicApiURL}/Data/Detail/${params.itemId}`, {
    cache: "no-store", // 禁用缓存,每次请求都获取最新数据
  });
  const data = await response.json();

  return <div>{/* 渲染内容 */}</div>;
}

方式三:客户端组件手动刷新数据(可选)

如果目标页面是客户端组件,可在页面加载时通过useEffect重新请求数据:

"use client";

import { useEffect, useState } from "react";
import { useParams } from "next/navigation";

export default function PathAPage() {
  const params = useParams();
  const [data, setData] = useState(null);

  useEffect(() => {
    const fetchData = async () => {
      const response = await fetch(`${publicApiURL}/Data/Detail/${params.itemId}`, {
        cache: "no-store",
      });
      const result = await response.json();
      setData(result);
    };

    fetchData();
  }, [params.itemId]);

  if (!data) return <div>Loading...</div>;

  return <div>{/* 渲染内容 */}</div>;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 21:48:10