平行路由(Parallel Routes)
平行路由指的是在同一布局
layout.tsx中,可以同时渲染多个页面,例如team,analytics等

基本用法
平行路由的使用方法就是通过@ + 文件夹名来定义,例如@team,@analytics等,名字可以自定义。
平行路由不会影响
URL路径。

定义完成之后,我们就可以在layout.tsx中使用team和analytics来渲染对应的页面,他会自动注入 layout 的 props 里面
注意:例子中我们使用了解构的语法,这里面的名称
team,analytics需跟文件夹名称一致。
export default function RootLayout({
children,
team,
analytics,
}: {
children: React.ReactNode;
team: React.ReactNode;
analytics: React.ReactNode;
}) {
return (
<html>
<body>
{team}
{children}
{analytics}
</body>
</html>
);
}独立路由
当我们使用了平行路由之后,我们为其单独定义
loading,error,等组件使其拥有独立加载和错误处理的能力。

default.tsx
首先我们先认识一下子导航,每一个平行路由下面还可以接着创建对应的路由,例如
@team下面可以接着创建@team/setting,@team/user等。
那我们的目录结构就是:
├── @team
│ ├── page.tsx
│ ├── setting
│ │ └── page.tsx
└── @analytics
│ └── page.tsx
└── layout.tsx
└── page.tsx然后我们使用Link组件跳转子导航setting页面
import Link from "next/link";
export default function RootLayout({
children,
team,
analytics,
}: {
children: React.ReactNode;
team: React.ReactNode;
analytics: React.ReactNode;
}) {
return (
<html>
<body>
{team}
{children}
{analytics}
<Link className="text-blue-500 block" href="/setting">
Setting
</Link>
</body>
</html>
);
}
观察上图我们发现,子导航使用Link组件跳转setting页面时,是没有问题的,但是我们在跳转之后刷新页面,就出现404了,这是怎么回事?
当使用软导航
Link组件跳转子页面的时候,这时候@analytics和children依然保持活跃,所以他只会替代@team里面的内容。而当我们使用硬导航浏览器页面刷新,此时
@analytics和children已经失活,因为它的底层原理其实是同时匹配@team和@analytics,children目录下面的setting页面,但是只有@team有这个页面,其他两个没有,所以导致404。 解决方案:使用default.tsx来进行兜底,确保不会404@analytics/default.tsx定义default.tsx文件app/default.tsx定义default.tsx文件

条件渲染
除了让它们同时展示,你也可以根据条件判断展示:

举例:实现 Modal
在实际开发中,平行路由可以用于渲染弹窗(
Modal)。

实现的效果是,当跳转到 /login 的时候,渲染 Modal。
写个示例代码。项目目录如下:
app
├─ layout.js
├─ page.js
└─ @auth
├─ page.js
├─ default.js
└─ login
└─ page.jsapp/layout.js代码如下:
// app/layout.js
import "./globals.css";
import Link from "next/link";
export default function RootLayout({ children, auth }) {
return (
<html>
<body>
<div>
<Link href="/login">Open Auth Modal</Link>
</div>
<div>
<Link href="/">Back To Home</Link>
</div>
<h1>/app/layout.js</h1>
{children}
{auth}
</body>
</html>
);
}app/page.js 代码如下:
// app/page.js
export default function Page() {
return <h1>/app/page.js</h1>;
}如果没有 @auth下的代码,此时访问 /,效果应该是:

考虑到我们写的是一个 Modal 效果,当我们访问 / 的时候,Modal 应该是不被渲染的。当我们访问其他地址如/about的时候,Modal 也不应该被渲染。所以app/@auth/page.js和 app/@auth/default.js都应该 return 一个 null。
两个文件代码如下:
// app/@auth/page.js
export default function Page() {
return null;
}// app/@auth/default.js
export default function Default() {
return null;
}app/@auth/login/page.js 代码如下:
// app/@auth/login/page.js
"use client";
import { useRouter } from "next/navigation";
export default function Page() {
const router = useRouter();
return (
<div
style={{
width: "200px",
height: "100px",
backgroundColor: "red",
position: "fixed",
top: "20px",
left: "220px",
}}
>
<span onClick={() => router.back()}>Close Modal</span>
<h1>Modal Content</h1>
</div>
);
}最终效果如下: 
当我们点击 Open Auth Modal的时候,路由跳转 /login,显示弹窗。点击弹窗里的 Close Modal,路由跳回 /,弹窗关闭。点击 Back To Home,从 /login 跳到 /,弹窗也会关闭。
之所以能实现这样一个功能,借助的就是平行路由的功能。当跳转到 /login 的时候,app/@auth/login/page.js 会作为 app/layout.js 中的 auth 参数传入,于是展示了弹窗。当跳转到 /的时候,展示 app/@auth/page.js,此时 return null,所以关闭了弹窗。
但是你可能发现一个问题,那就是当我们刷新 /login页面的时候,会出现 404 错误。刷新后的结果如下:

为什么会出现这样一个内容呢?
经过排查,这个 404 提示来自于 app/layout.js 中的 children。如果你把 {children}这行代码删除,就不会展示这个错误。(一般来说,不会这样做,只需加上 default.js 文件,就可以解决这个问题。)
...
export default function RootLayout({ children, auth }) {
return (
...
<h1>/app/layout.js</h1>
{children}
{auth}
...
)
}其实你把 children 理解为另外一个插槽就方便理解了。/app/page.js相当于 app/@children/page.js。
当访问 /login 的时候,只匹配了 /@auth/login/page.js 这个插槽,但是 /@children/page.js 就没有匹配到了。
当重新刷新的时候,Next.js 会首先尝试渲染不匹配插槽的 default.js 文件,如果不可用,再渲染 404。
所以解决这个问题也很简单,在 app 下新建一个 default.js 文件,也 return null 就可以了:
export default function Default() {
return null;
}此时再刷新 /login 页面,就没有 404 错误了:
