Route File Naming
路由文件命名
虽然您可以通过 routes
插件选项 配置路由,但大多数路由都是使用此文件系统约定创建的。添加文件,获取路由。
请注意,您可以使用 .js
、.jsx
、.ts
或 .tsx
文件扩展名。为了避免重复,我们将在示例中使用 .tsx
。
免责声明
不过,在深入探讨 Remix 惯例之前,我们想指出,基于文件的路由是一个极其主观的想法。有些人喜欢扁平
路由的想法,有些人讨厌它,更喜欢将路由嵌套在文件夹中。有些人只是讨厌基于文件的路由,更喜欢通过 JSON 配置路由。有些人更喜欢通过 JSX 配置路由,就像他们在 React Router SPA 中所做的那样。
重点是,我们非常清楚这一点,从一开始,Remix 就一直为您提供一流的退出方式,即通过 routes
/ignoredRouteFiles
和 手动配置您的路由。但是,必须有一些默认设置,以便人们可以快速轻松地启动和运行 - 我们认为下面的扁平路由约定文档是一个非常好的默认设置,可以很好地扩展到中小型应用程序。
无论您使用哪种约定,拥有数百或数千条路由的大型应用程序总是会有点混乱 - 而我们的想法是通过路由
配置,您可以构建最适合您的应用程序/团队的约定。对于 Remix 来说,拥有一个让每个人都满意的默认约定几乎是不可能的。我们宁愿为您提供一个相当简单的默认约定,然后让社区构建任意数量的约定供您挑选。
因此,在我们深入了解 Remix 默认约定的细节之前,如果您认为我们的默认约定不合您的心意,您可以查看以下一些社区替代方案。
remix-flat-routes
- Remix 默认基本上是此包的简化版本。作者继续迭代和改进此包,因此如果您总体上喜欢平面路由
的想法,但想要更强大的功能(包括文件和文件夹的混合方法),请务必查看此包。remix-custom-routes
- 如果您想要更多自定义,此包允许您定义应将哪些类型的文件视为路由。这让您超越简单的平面/嵌套概念,并执行诸如任何扩展名为
.route.tsx的文件都是路由
之类的操作。remix-json-routes
- 如果您只想通过配置文件指定路由,那么这就是您的选择 - 只需为 Remix 提供一个带有路由的 JSON 对象,并完全跳过平面/嵌套概念。其中甚至还有一个 JSX 选项。
根路由
app/root.tsx
中的文件是您的根布局,或根路由
(对于那些发音相同的人,非常抱歉!)。它的工作方式与所有其他路由一样,因此您可以导出 loader
、action
等。
根路由通常看起来像这样。它作为整个应用程序的根布局,所有其他路由将在 <Outlet />
内呈现。
基本路由
app/routes
目录中的任何 JavaScript 或 TypeScript 文件都将成为应用程序中的路由。文件名映射到路由的 URL 路径名,但 _index.tsx
除外,它是 根路由 的 索引路由。
URL | Matched Routes |
---|---|
/ | app/routes/_index.tsx |
/about | app/routes/about.tsx |
请注意,由于嵌套路由,这些路由将在app/root.tsx
的出口中呈现。
点分隔符
在路由文件名中添加。
将在 URL 中创建/
。
URL | Matched Route |
---|---|
/ | app/routes/_index.tsx |
/about | app/routes/about.tsx |
/concerts/trending | app/routes/concerts.trending.tsx |
/concerts/salt-lake-city | app/routes/concerts.salt-lake-city.tsx |
/concerts/san-diego | app/routes/concerts.san-diego.tsx |
点分隔符也会创建嵌套,有关更多信息,请参阅嵌套部分。
动态细分
通常,您的 URL 不是静态的,而是由数据驱动的。动态段允许您匹配 URL 的段并在代码中使用该值。您可以使用 $
前缀创建它们。
URL | Matched Route |
---|---|
/ | app/routes/_index.tsx |
/about | app/routes/about.tsx |
/concerts/trending | app/routes/concerts.trending.tsx |
/concerts/salt-lake-city | app/routes/concerts.$city.tsx |
/concerts/san-diego | app/routes/concerts.$city.tsx |
Remix 会解析 URL 中的值并将其传递给各种 API。我们将这些值称为URL 参数
。访问 URL 参数最有用的位置是 loaders 和 actions。
您会注意到params
对象上的属性名称直接映射到文件的名称:$city.tsx
变成params.city
。
路由可以有多个动态段,例如concerts.$city.$date
,均可通过名称在 params 对象上访问:
有关更多信息,请参阅路由指南。
嵌套路由
嵌套路由的一般思路是将 URL 的各个部分与组件层次结构和数据耦合起来。您可以在 路由指南 中阅读更多相关信息。
您可以使用 点分隔符 创建嵌套路由。如果 .
之前的文件名与另一个路由文件名匹配,则它会自动成为匹配父路由的子路由。请考虑以下路由:
所有以app/routes/concerts.
开头的路由将成为app/routes/concerts.tsx
的子路由,并在父路由的outlet_component 内呈现。
URL | Matched Route | Layout |
---|---|---|
/ | app/routes/_index.tsx | app/root.tsx |
/about | app/routes/about.tsx | app/root.tsx |
/concerts | app/routes/concerts._index.tsx | app/routes/concerts.tsx |
/concerts/trending | app/routes/concerts.trending.tsx | app/routes/concerts.tsx |
/concerts/salt-lake-city | app/routes/concerts.$city.tsx | app/routes/concerts.tsx |
请注意,您通常需要在添加嵌套路由时添加索引路由,以便当用户直接访问父级 URL 时,某些内容会在父级出口内呈现。
例如,如果 URL 是 /concerts/salt-lake-city
,那么 UI 层次结构将如下所示:
嵌套 URL,无需布局嵌套
有时您希望 URL 嵌套,但不希望自动布局嵌套。您可以在父段后面添加下划线来选择退出嵌套:
URL | Matched Route | Layout |
---|---|---|
/ | app/routes/_index.tsx | app/root.tsx |
/about | app/routes/about.tsx | app/root.tsx |
/concerts/mine | app/routes/concerts_.mine.tsx | app/root.tsx |
/concerts/trending | app/routes/concerts.trending.tsx | app/routes/concerts.tsx |
/concerts/salt-lake-city | app/routes/concerts.$city.tsx | app/routes/concerts.tsx |
请注意,/concerts/mine
不再与app/routes/concerts.tsx
嵌套,而是app/root.tsx
。下划线trailing_
创建了路径段,但不会创建布局嵌套。
把 trailing_
下划线想象成你父母签名末尾的长段,将你从遗嘱中写出来,从布局嵌套中删除后面的部分。
嵌套布局,无需嵌套 URL
我们称之为无路径路由
有时,您希望与一组路由共享布局,而无需向 URL 添加任何路径段。一个常见示例是一组身份验证路由,其页眉/页脚与公共页面或登录应用体验不同。您可以使用 _leading
下划线来实现此目的。
URL | Matched Route | Layout |
---|---|---|
/ | app/routes/_index.tsx | app/root.tsx |
/login | app/routes/_auth.login.tsx | app/routes/_auth.tsx |
/register | app/routes/_auth.register.tsx | app/routes/_auth.tsx |
/concerts | app/routes/concerts.tsx | app/root.tsx |
/concerts/salt-lake-city | app/routes/concerts.$city.tsx | app/routes/concerts.tsx |
可以将 _leading
下划线想象成一条盖在文件名上的毯子,将文件名从 URL 中隐藏起来。
可选段
将路由段括在括号中将使该段成为可选的。
URL | Matched Route |
---|---|
/ | app/routes/($lang)._index.tsx |
/categories | app/routes/($lang).categories.tsx |
/en/categories | app/routes/($lang).categories.tsx |
/fr/categories | app/routes/($lang).categories.tsx |
/american-flag-speedo | app/routes/($lang)._index.tsx |
/en/american-flag-speedo | app/routes/($lang).$productId.tsx |
/fr/american-flag-speedo | app/routes/($lang).$productId.tsx |
您可能想知道为什么 /american-flag-speedo
与 ($lang)._index.tsx
路由匹配,而不是 ($lang).$productId.tsx
。这是因为当您有一个可选的动态参数段后跟另一个动态参数时,Remix 无法可靠地确定单段 URL(例如 /american-flag-speedo
)是否应匹配 /:lang
/:productId
。可选段会积极匹配,因此它将匹配 /:lang
。如果您有这种类型的设置,建议查看 ($lang)._index.tsx
加载器中的 params.lang
,如果 params.lang
不是有效的语言代码,则重定向到当前/默认语言的 /:lang/american-flag-speedo
。
Splat 路由
虽然 动态段 匹配单个路径段(URL 中两个 /
之间的内容),但 splat 路由将匹配 URL 的其余部分,包括斜杠。
URL | Matched Route |
---|---|
/ | app/routes/_index.tsx |
/about | app/routes/about.tsx |
/beef/and/cheese | app/routes/$.tsx |
/files | app/routes/files.$.tsx |
/files/talks/remix-conf_old.pdf | app/routes/files.$.tsx |
/files/talks/remix-conf_final.pdf | app/routes/files.$.tsx |
/files/talks/remix-conf-FINAL-MAY_2022.pdf | app/routes/files.$.tsx |
与动态路由参数类似,您可以使用 "*"
键访问 splat 路由的 params
上匹配路径的值。
转义特殊字符
如果您希望 Remix 用于这些路由约定的特殊字符之一实际上成为 URL 的一部分,则可以使用 []
字符转义这些约定。
Filename | URL |
---|---|
app/routes/sitemap[.]xml.tsx | /sitemap.xml |
app/routes/[sitemap.xml].tsx | /sitemap.xml |
app/routes/weird-url.[_index].tsx | /weird-url/_index |
app/routes/dolla-bills-[$].tsx | /dolla-bills-$ |
app/routes/[[so-weird]].tsx | /[so-weird] |
组织文件夹
路由也可以是文件夹,其中包含定义路由模块的route.tsx
文件。文件夹中的其余文件不会成为路由。这样,您就可以更接近使用它们的路由来组织代码,而不是在其他文件夹中重复功能名称。
考虑以下路由:
它们中的一些或者全部都可以是包含其自己的路由
模块的文件夹。
注意,当你将路由模块放入文件夹时,该路由模块将变为folder/route.tsx
,文件夹中的所有其他模块都不会成为路由。例如:
缩放
我们对扩展的一般建议是将每条路由都设为一个文件夹,并将该路由专用的模块放在该文件夹中,然后将共享模块放在路由文件夹之外的其他位置。这有几个好处:
- 易于识别共享模块,因此在更改它们时要小心谨慎
- 易于组织和重构特定路由的模块,而不会造成
文件组织疲劳
并使应用程序的其他部分变得混乱