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

NextJS 13二级动态嵌套路由实现:复用增改表单路由方案求助

问题:NextJS 13实现二级动态嵌套路由并复用增改表单代码

现有路由结构:

(user)/dashboard/profile/trainee/[userId]/page.tsx

新增表单路由:

(user)/dashboard/profile/trainee/[userId]/escort/addEdit/page.tsx

期望实现:

  • 添加编辑表单路由(user)/dashboard/profile/trainee/[userId]/escort/[escortId]/page.tsx
  • 编辑路由与新增路由复用同一套表单代码
  • 尝试使用可选捕获路由[[slug]]时出现报错:
    Error: You cannot define a route with the same specificity as a optional catch-all route ("/dashboard/profile/trainee/[userId]" and "/dashboard/profile/trainee/[userId][[...slug]]").
    

解决方案

方法一:抽离表单组件,多路由复用核心逻辑

这是最直接的方案,把表单的核心逻辑抽成独立组件,让新增和编辑路由分别引用该组件并传递对应参数。

  1. 抽离表单核心组件
    在(user)/dashboard/profile/trainee/[userId]/escort/components/目录下创建EscortForm.tsx,将原addEdit/page.tsx中的表单UI、增改逻辑迁移到这里,组件接收可选的escortId参数来区分新增/编辑场景:
'use client';
import { useEffect, useState } from 'react';

interface EscortFormProps {
  escortId?: string;
}

export default function EscortForm({ escortId }: EscortFormProps) {
  const [formData, setFormData] = useState({ name: '', phone: '' });
  const userId = typeof window !== 'undefined' ? window.location.pathname.split('/')[5] : '';

  // 编辑场景:加载已有数据
  useEffect(() => {
    if (!escortId) return;
    fetch(`/api/trainees/${userId}/escorts/${escortId}`)
      .then(res => res.json())
      .then(data => setFormData(data));
  }, [escortId, userId]);

  // 提交逻辑:区分新增/编辑
  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    const options = {
      method: escortId ? 'PUT' : 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(formData)
    };

    const url = escortId 
      ? `/api/trainees/${userId}/escorts/${escortId}` 
      : `/api/trainees/${userId}/escorts`;

    await fetch(url, options);
    // 提交后跳转或提示逻辑
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        value={formData.name}
        onChange={(e) => setFormData({...formData, name: e.target.value})}
        placeholder="陪同人姓名"
        required
      />
      <input
        type="tel"
        value={formData.phone}
        onChange={(e) => setFormData({...formData, phone: e.target.value})}
        placeholder="联系电话"
        required
      />
      <button type="submit">{escortId ? '保存修改' : '新增陪同'}</button>
    </form>
  );
}
  1. 修改新增路由页面
    addEdit/page.tsx直接渲染抽离的表单组件,不传递escortId:
// (user)/dashboard/profile/trainee/[userId]/escort/addEdit/page.tsx
import EscortForm from '../components/EscortForm';

export default function AddEscortPage() {
  return <EscortForm />;
}
  1. 创建编辑路由页面
    [escortId]/page.tsx获取路由参数后传递给表单组件:
// (user)/dashboard/profile/trainee/[userId]/escort/[escortId]/page.tsx
import { useParams } from 'next/navigation';
import EscortForm from '../components/EscortForm';

export default function EditEscortPage() {
  const params = useParams();
  return <EscortForm escortId={params.escortId as string} />;
}

方法二:路由重写,通过查询参数复用页面

利用NextJS的路由重写功能,将编辑路由映射到新增路由,通过查询参数传递escortId,无需新增额外的page文件。

  1. 配置路由重写
    在next.config.js中添加重写规则:
/** @type {import('next').NextConfig} */
const nextConfig = {
  async rewrites() {
    return [
      {
        source: '/dashboard/profile/trainee/:userId/escort/:escortId',
        destination: '/dashboard/profile/trainee/:userId/escort/addEdit?escortId=:escortId',
      },
    ];
  },
};

module.exports = nextConfig;
  1. 修改新增页面逻辑
    在addEdit/page.tsx中获取查询参数,传递给表单组件:
// (user)/dashboard/profile/trainee/[userId]/escort/addEdit/page.tsx
'use client';
import { useSearchParams } from 'next/navigation';
import EscortForm from '../components/EscortForm';

export default function AddEditPage() {
  const searchParams = useSearchParams();
  const escortId = searchParams.get('escortId');
  
  return <EscortForm escortId={escortId || undefined} />;
}

方案对比

  • 方法一:路由结构清晰,语义明确,适合需要直观路由层级的场景,维护性强;
  • 方法二:减少页面文件数量,适合轻量化场景,但实际访问的是重写后的路由,需注意SEO和链接一致性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 16:18:28