@react-router/fs-routes
套件啟用基於檔案慣例的路由配置。
首先安裝 @react-router/fs-routes
套件
npm i @react-router/fs-routes
然後使用它在您的 app/routes.ts
檔案中提供路由配置
import { type RouteConfig } from "@react-router/dev/routes";
import { flatRoutes } from "@react-router/fs-routes";
export default flatRoutes() satisfies RouteConfig;
預設情況下,app/routes
目錄中的任何模組都將成為應用程式中的路由。ignoredRouteFiles
選項允許您指定不應包含為路由的檔案
import { type RouteConfig } from "@react-router/dev/routes";
import { flatRoutes } from "@react-router/fs-routes";
export default flatRoutes({
ignoredRouteFiles: ["home.tsx"],
}) satisfies RouteConfig;
這將預設在 app/routes
目錄中尋找路由,但這可以通過相對於您的應用程式目錄的 rootDirectory
選項進行配置
import { type RouteConfig } from "@react-router/dev/routes";
import { flatRoutes } from "@react-router/fs-routes";
export default flatRoutes({
rootDirectory: "file-routes",
}) satisfies RouteConfig;
本指南的其餘部分將假設您正在使用預設的 app/routes
目錄。
檔名映射到路由的 URL 路徑名稱,但 _index.tsx
除外,它是索引路由,適用於根路由。您可以使用 .js
、.jsx
、.ts
或 .tsx
檔案擴展名。
app/
├── routes/
│ ├── _index.tsx
│ └── about.tsx
└── root.tsx
網址 | 匹配的路由 |
---|---|
/ |
app/routes/_index.tsx |
/about |
app/routes/about.tsx |
請注意,由於巢狀路由,這些路由將在 app/root.tsx
的 outlet 中呈現。
在路由檔名中新增 .
將在 URL 中建立 /
。
app/
├── routes/
│ ├── _index.tsx
│ ├── about.tsx
│ ├── concerts.trending.tsx
│ ├── concerts.salt-lake-city.tsx
│ └── concerts.san-diego.tsx
└── root.tsx
網址 | 匹配的路由 |
---|---|
/ |
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 的區段,並在您的程式碼中使用該值。您可以使用 $
字首建立它們。
app/
├── routes/
│ ├── _index.tsx
│ ├── about.tsx
│ ├── concerts.$city.tsx
│ └── concerts.trending.tsx
└── root.tsx
網址 | 匹配的路由 |
---|---|
/ |
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 |
該值將從 URL 中解析,並傳遞到各種 API。我們將這些值稱為「URL 參數」。存取 URL 參數最有用的地方是在loaders 和actions 中。
export async function serverLoader({ params }) {
return fakeDb.getAllConcertsForCity(params.city);
}
您會注意到 params
物件上的屬性名稱直接映射到您的檔案名稱:$city.tsx
變成 params.city
。
路由可以有多個動態區段,例如 concerts.$city.$date
,兩者都可以通過名稱在 params 物件上存取
export async function serverLoader({ params }) {
return fake.db.getConcerts({
date: params.date,
city: params.city,
});
}
有關更多資訊,請參閱路由指南。
巢狀路由是將 URL 區段耦合到元件層級結構和資料的一般概念。您可以在路由指南中閱讀更多相關資訊。
您可以使用點分隔符建立巢狀路由。如果 .
之前的檔名與另一個路由檔名匹配,它會自動成為匹配父項的子路由。考慮以下路由
app/
├── routes/
│ ├── _index.tsx
│ ├── about.tsx
│ ├── concerts._index.tsx
│ ├── concerts.$city.tsx
│ ├── concerts.trending.tsx
│ └── concerts.tsx
└── root.tsx
所有以 app/routes/concerts.
開頭的路由都將是 app/routes/concerts.tsx
的子路由,並在父路由的 outlet 內呈現。
網址 | 匹配的路由 | 版面配置 |
---|---|---|
/ |
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 時,在父項的 outlet 內呈現某些內容。
例如,如果 URL 是 /concerts/salt-lake-city
,則 UI 層級結構將如下所示
<Root>
<Concerts>
<City />
</Concerts>
</Root>
有時您希望 URL 是巢狀的,但您不希望自動版面配置巢狀結構。您可以使用父區段上的尾隨底線選擇退出巢狀結構
app/
├── routes/
│ ├── _index.tsx
│ ├── about.tsx
│ ├── concerts.$city.tsx
│ ├── concerts.trending.tsx
│ ├── concerts.tsx
│ └── concerts_.mine.tsx
└── root.tsx
網址 | 匹配的路由 | 版面配置 |
---|---|---|
/ |
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 新增任何路徑區段。一個常見的範例是一組身份驗證路由,它們具有與公共頁面或已登入應用程式體驗不同的標頭/頁尾。您可以使用 _leading
底線來執行此操作。
app/
├── routes/
│ ├── _auth.login.tsx
│ ├── _auth.register.tsx
│ ├── _auth.tsx
│ ├── _index.tsx
│ ├── concerts.$city.tsx
│ └── concerts.tsx
└── root.tsx
網址 | 匹配的路由 | 版面配置 |
---|---|---|
/ |
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/routes/concerts.tsx |
/concerts/salt-lake-city |
app/routes/concerts.$city.tsx |
app/routes/concerts.tsx |
將 _leading
底線視為您拉到檔名上的毯子,將檔名從 URL 中隱藏起來。
將路由區段括在括號中將使該區段成為可選的。
app/
├── routes/
│ ├── ($lang)._index.tsx
│ ├── ($lang).$productId.tsx
│ └── ($lang).categories.tsx
└── root.tsx
網址 | 匹配的路由 |
---|---|
/ |
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
。這是因為當您有一個可選的動態參數區段,後跟另一個動態參數時,無法可靠地判斷單區段 URL(例如 /american-flag-speedo
)是否應該匹配 /:lang
/:productId
。可選區段會積極匹配,因此它將匹配 /:lang
。如果您有這種設定,建議您在 ($lang)._index.tsx
loader 中查看 params.lang
,並將 /:lang/american-flag-speedo
重定向到目前/預設語言(如果 params.lang
不是有效的語言代碼)。
雖然動態區段匹配單一路徑區段(URL 中兩個 /
之間的部分),但 splat 路由將匹配 URL 的其餘部分,包括斜線。
app/
├── routes/
│ ├── _index.tsx
│ ├── $.tsx
│ ├── about.tsx
│ └── files.$.tsx
└── root.tsx
網址 | 匹配的路由 |
---|---|
/ |
app/routes/_index.tsx |
/about |
app/routes/about.tsx |
/beef/and/cheese |
app/routes/$.tsx |
/files |
app/routes/files.$.tsx |
/files/talks/react-conf_old.pdf |
app/routes/files.$.tsx |
/files/talks/react-conf_final.pdf |
app/routes/files.$.tsx |
/files/talks/react-conf-FINAL-MAY_2024.pdf |
app/routes/files.$.tsx |
與動態路由參數類似,您可以使用 "*"
鍵在 splat 路由的 params
上存取匹配路徑的值。
export async function serverLoader({ params }) {
const filePath = params["*"];
return fake.getFileInfo(filePath);
}
如果您希望用於這些路由慣例的特殊字元實際上是 URL 的一部分,您可以使用 []
字元跳脫慣例。這對於資源路由(包括 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] |
app/routes/reports.$id[.pdf].ts |
/reports/123.pdf |
路由也可以是資料夾,其中包含定義路由模組的 route.tsx
檔案。資料夾中的其餘檔案不會成為路由。這允許您更靠近使用它們的路由來組織您的程式碼,而不是在其他資料夾中重複功能名稱。
資料夾內的檔案對於路由路徑沒有意義,路由路徑完全由資料夾名稱定義。
考慮以下路由
app/
├── routes/
│ ├── _landing._index.tsx
│ ├── _landing.about.tsx
│ ├── _landing.tsx
│ ├── app._index.tsx
│ ├── app.projects.tsx
│ ├── app.tsx
│ └── app_.projects.$id.roadmap.tsx
└── root.tsx
它們中的一些或全部可以是資料夾,其中包含它們自己的 route
模組。
app/
├── routes/
│ ├── _landing._index/
│ │ ├── route.tsx
│ │ └── scroll-experience.tsx
│ ├── _landing.about/
│ │ ├── employee-profile-card.tsx
│ │ ├── get-employee-data.server.ts
│ │ ├── route.tsx
│ │ └── team-photo.jpg
│ ├── _landing/
│ │ ├── footer.tsx
│ │ ├── header.tsx
│ │ └── route.tsx
│ ├── app._index/
│ │ ├── route.tsx
│ │ └── stats.tsx
│ ├── app.projects/
│ │ ├── get-projects.server.ts
│ │ ├── project-buttons.tsx
│ │ ├── project-card.tsx
│ │ └── route.tsx
│ ├── app/
│ │ ├── footer.tsx
│ │ ├── primary-nav.tsx
│ │ └── route.tsx
│ ├── app_.projects.$id.roadmap/
│ │ ├── chart.tsx
│ │ ├── route.tsx
│ │ └── update-timeline.server.ts
│ └── contact-us.tsx
└── root.tsx
請注意,當您將路由模組變成資料夾時,路由模組會變成 folder/route.tsx
,資料夾中的所有其他模組都不會變成路由。例如
# these are the same route:
app/routes/app.tsx
app/routes/app/route.tsx
# as are these
app/routes/app._index.tsx
app/routes/app._index/route.tsx