remix-logo

Remix Nested Route(嵌套路由) Explained

對剛開始學 Remix 的人,他的路由系統應該會看得很辛苦,沒關係我也是,所以就寫了這篇來記錄一下該怎麼好好的寫好這些路由。

Reference: https://remix.run/docs/en/main/components/outlethttps://remix.run/docs/en/main/file-conventions/routes
解釋影片:https://www.youtube.com/watch?v=QONJCXsZt58
Route Demo:https://interactive-remix-routing-v2.netlify.app

Remix Route 名詞解釋

1. Route

在你的 route 裡面,長 your_route.tsx 會自動產生一個 route,可以從 /your_route 進入。在 Filing 系統中,你的檔案夾名稱就會是 route,而 Remix 會自動取得檔案夾下面的 route.tsx 檔案,例如你儲存 app/your_route/route.tsx,就等於你直接使用 app/your_route.tsx。

2. Parent

每個 Route 只要在檔案裡面加入 <Outlet />,就會變成 Parent,然後在 Outlet 的地方渲染 Child,可以傳遞 context={data} 給 Child。

3. Child

在 Child 內使用 useOutletContext() 取得 Parent 傳來的 context data。例如 your_route.tsx 是你的 parent,child 是 your_route.child.tsx,你可以前往 /your_route/child。

4. Index

每個 route parent 檔案裡如果包含 <Outlet />,你就可以使用 your_route._index.tsx 來作為 /your_route 的 Outlet,所以前往 /your_route 會在 Outlet 渲染 index 的檔案。

5. Dynamic route

可以使用 your_route.$your_id.tsx 來產生動態 route,前往 /your_route/abc,你就可以在檔案內呼叫 params 取得 abc。

Flat routing & Folder routing in Remix

在 V2,Remix 已經不支援 Folder Nesting 了,而是保持 Flat Route,我想應該是因為 name routing 就可以排序,不需要多此一局使用 Folder。可以看看下面兩個連結,也可以看出 Remix 真是會聽使用者意見欸!

>> Upgrading to the new convention: https://remix.run/docs/en/main/start/v2#upgrading-to-the-new-convention
>> Origin Flat Route Proposal: https://github.com/remix-run/remix/discussions/4482

Route Explanation from remix.run

上圖可以看到 Invoice id 從 Invoices 的 <Outlet /> 長出來;Invoices 從 Sales 的 <Outlet /> 長出來;Sales 從 Root 的 <Outlet /> 長出來。

最基本的 Remix Route

// app/route/parent.tsx

export default function SomeParent() {
  return (
    <>
      <div>
        <h1>Parent Content</h1>
      </div>
    </>
  );
}

加入 Outlet 讓他變成 Parent

加入 Outlet

// app/route/parent.tsx

import { Outlet } from "@remix-run/react";

export default function SomeParent() {
  const myContextValue = { foo: "bar" };

  return (
    <>
        <div className="parent-content">
            <h1>Parent Content</h1>
            <Outlet context={myContextValue} />
            <p>{JSON.stringify(myContextValue)}</p>
        </div>
    </>
  );
}

加入 parent._index.tsx

export default function Child_index() {
  return (
    <div>
      <h1>Index</h1>
    </div>
  );
}

有漸漸理解了嗎?Index 從 parent.tsx 的 Outlet 長出來了!

加入 Child

// parent.child.tsx

import { useOutletContext } from "@remix-run/react"

export default function Child() {
  const myContextValue = useOutletContext();
  
  return (
    <>
      <p>this is child + {JSON.stringify(myContextValue)}</p>
    </>
  );
}

可以看到 Parent Content 和最後的<p> {“foo”:”bar”} 是來自 Parent,而<p> this is child + {} 是來自 child。如此就跟官網所說的一樣了!