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

Next.js提交表单后router.query丢失name参数致数据加载失败

解决Next.js详情页提交表单后name参数丢失的问题

问题根源

你通过next/link跳转时给详情页传递了id和name两个参数,但因为详情页是[id].js动态路由,URL里只会显示/clients/xxx(xxx为id值),name只是临时的查询参数。表单提交后刷新页面,浏览器只会保留URL里的路径部分,查询参数name不会被持久化,导致router.query里只剩下id,进而让fetchInvoices接口因为缺少name参数无法正常获取数据。

解决方案

方案1:修改后端接口,仅用id获取发票(最推荐)

name不是唯一标识,存在重复或变更的可能,依赖它查询数据本身就不合理。直接让后端支持通过客户id查询发票:

  • 后端调整/clients/${id}/fetch接口,去掉client查询参数,改用id关联查询发票
  • 前端修改fetchInvoices函数:
const fetchInvoices = async () => {
  const invoices = await axios.get(
    `http://localhost:5010/clients/${id}/invoices` // 替换为新的接口地址
  );
  setClientInvoices(invoices.data);
};

这样不管URL里有没有name,只要有id就能拿到正确的发票数据,从根源解决问题。

方案2:持久化name查询参数到URL

如果暂时没法改后端,可以在表单提交后手动把name参数加回URL,确保刷新时能拿到:

  1. 给Form组件传入router和id参数(从ClientTitle往下传递):
// ClientTitle.jsx中修改Form的调用
{showForm && <Form name={title} router={router} id={clientId} />}
  1. 修改Form的handleSubmit,提交后重定向回详情页并带上参数:
const handleSubmit = async (e) => {
  e.preventDefault(); // 必须阻止表单默认提交行为,避免页面硬刷新
  await axios.post("http://localhost:5010/clients/invoices", clientInvoice);
  // 重定向时带上id和name,确保URL包含查询参数
  router.push({
    pathname: `/clients/${id}`,
    query: { id: id, name: name }
  });
};
  1. 额外做兜底处理:即使router.query.name丢失,用clientData.name替代
    修改详情页的useEffect和fetchInvoices:
const fetchInvoices = async (clientName) => {
  const invoices = await axios.get(
    `http://localhost:5010/clients/${id}/fetch?client=${clientName}`
  );
  setClientInvoices(invoices.data);
};

useEffect(() => {
  if (router.isReady) {
    fetchData().then(() => {
      // 优先用clientData里的name,没有再用router.query.name
      fetchInvoices(clientData.name || name);
    });
  }
}, [router.isReady, clientData.name]);

方案3:用服务端渲染预取数据

用Next.js的getServerSideProps在服务端获取数据,直接把clientData和clientInvoices作为props传给组件,不用依赖前端的router.query:
修改[id].js:

import axios from "axios";
import ClientTitle from "./ClientTitle";

const ClientInfo = ({ clientData, clientInvoices }) => {
  return (
    <div>
      <ClientTitle
        title={clientData.name}
        balance={clientData.balance}
        clientId={clientData.clientId}
      />
      <div>
        <div>
          <span>Date</span>
          <span>From</span>
          <span>To</span>
          <span>Price</span>
        </div>
        {clientInvoices &&
          clientInvoices.map((invoice) => (
            <div key={invoice._id}>
              <div>{invoice.date}</div>
              <div>{invoice.from}</div>
              <div>{invoice.to}</div>
              <div>{invoice.price}</div>
            </div>
          ))}
      </div>
    </div>
  );
};

export async function getServerSideProps(context) {
  const { id } = context.params;
  try {
    // 先获取客户信息
    const clientRes = await axios.get(`http://localhost:5010/clients/${id}`);
    const clientData = clientRes.data;
    // 再用客户name获取发票
    const invoicesRes = await axios.get(
      `http://localhost:5010/clients/${id}/fetch?client=${clientData.name}`
    );
    return {
      props: {
        clientData,
        clientInvoices: invoicesRes.data
      }
    };
  } catch (err) {
    // 处理错误,返回空数据或重定向
    return {
      props: { clientData: {}, clientInvoices: [] }
    };
  }
}

export default ClientInfo;

这样页面加载时直接从服务端拿到数据,完全不受前端路由参数丢失的影响。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 22:05:26