kiliman / remix-flat-routes

Remix package to define routes using the flat-routes convention
MIT License
640 stars 22 forks source link

Issue with the use of multiple dynamic routes #86

Open jsimpson-vojo opened 7 months ago

jsimpson-vojo commented 7 months ago

We have a use case where we have multiple dynamics routes for different parents and want split it into distinct folders. for instance:

/nodes/$nodeId
/schedules/$scheduleId

The problem is that it will render the first one alphabetically (from what we can see) but when navigating to the schedules ID page it will route to the node ID page but still try to render the Schedules ID page and error out. Can someone explain why this would be the case?

It works when we use the flat structure: schedules_.$scheduleId but when splitting into the folder structure below we get the problems stated.

Our folder structure is as so:

Screenshot 2023-11-23 at 15 01 44
kiliman commented 7 months ago

Hmm... this route structure seems odd.

Remember, with hybrid routes, the /+ is replaced with . to the equivalent flat-files convention.

_nodes+/$nodeId+/$nodeId.tsx => _nodes.$nodeId.$nodeId.tsx
_schedules+/$scheduleId+/$scheduleId.tsx => _schedules.$scheduleId.$scheduleId.tsx

I'm guessing your intention here, but this is how I think the routes should be.

❯ tree app/routes
app/routes
├── nodes+
│   ├── $nodeId.tsx              /nodes/:nodeId  (with _layout)
│   ├── _.$nodeId.calls.tsx      /nodes/:nodeId/calls  (without _layout)     
│   ├── _.add.tsx                /nodes/add  (without _layout)     
│   └── _layout.tsx              layout for /nodes/*     
└── schedules+
    ├── $scheduleId.tsx          /schedules/:scheduleId  (with _layout)     
    ├── _layout.tsx              layout for /schedules/*
    ├── delete.tsx               /schedules/delete  (with _layout)     
    ├── history.tsx              /schedules/history  (with _layout)     
    └── new.tsx                  /schedules/new  (with _layout)     
<Routes>
  <Route file="root.tsx">
    <Route path="nodes/:nodeId/calls" file="routes/nodes+/_.$nodeId.calls.tsx" />
    <Route path="nodes/add" file="routes/nodes+/_.add.tsx" />
    <Route path="nodes" file="routes/nodes+/_layout.tsx">
      <Route path=":nodeId" file="routes/nodes+/$nodeId.tsx" />
    </Route>
    <Route path="schedules" file="routes/schedules+/_layout.tsx">
      <Route path=":scheduleId" file="routes/schedules+/$scheduleId.tsx" />
      <Route path="delete" file="routes/schedules+/delete.tsx" />
      <Route path="history" file="routes/schedules+/history.tsx" />
      <Route path="new" file="routes/schedules+/new.tsx" />
    </Route>
  </Route>
</Routes>

Notes:

The _ prefix is a pathless route, so will not be included in the URL. But your examples show you want /nodes and /schedules, so I removed the leading _.

Your example also had routes with duplicate params. $nodeId+/$nodeId is treated as :nodeId/:nodeId which doesn't make sense. I'm surprised Remix doesn't throw an error as this is technically an invalid route. Remember, with params, Remix will match any text for that segment. Since you technically had 2 routes with :param/:param, Remix matched any URL that was /anything/something to the :nodeId/:nodeId route (the first defined route).

nodes+/_layout.tsx is equivalent to nodes.tsx and is the parent layout for all /nodes/* routes.

The nodes+/_. prefix is like adding the _ suffix to the parent layout to opt out. nodes+/_.add.tsx is equivalent to nodes_.add.tsx

jsimpson-vojo commented 7 months ago

Thanks for your help! Has cleared some misunderstandings we were having.

kiliman commented 7 months ago

No problem. Reach out if you need further assistance.