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,确保刷新时能拿到:
- 给
Form组件传入router和id参数(从ClientTitle往下传递):
// ClientTitle.jsx中修改Form的调用 {showForm && <Form name={title} router={router} id={clientId} />}
- 修改
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 } }); };
- 额外做兜底处理:即使
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
相关产品推荐
相关产品推荐

