solid-router icon indicating copy to clipboard operation
solid-router copied to clipboard

Getting params in wrapped/nested routes

Open EthanYidong opened this issue 3 years ago • 4 comments

import { Outlet } from "solid-app-router";

function PageWrapper () {
  return <div>
    <h1> We love our users! </h1>
    <Outlet/>
    <Link href="/">Back Home</Link>
  </div>
}

<Route path="/users" element={<PageWrapper/>}>
  <Route path="/" element={<Users/>} />
  <Route path="/:id" element={<User/>} />
</Route>

In this example, it seems that there is no way to get the "id" parameter from within the PageWrapper component. This is, as far as I can tell, due to parameters not being held by the global Router context, but rather the local Route context. Are there any workarounds for this?

EthanYidong avatar Jun 02 '22 18:06 EthanYidong

If this is not intended, I am open to creating a pull request for this, however, changing the current behavior of useParams to pull from the global router may break some code which expects to only get parameters from the current Route context provider. To avoid that, should I create a new function such as useGlobalParams?

EthanYidong avatar Jun 02 '22 19:06 EthanYidong

I was just stumbling on the same issue and came here hoping to see a recent change or old resolved issue. I expected I would be able to access data provided by useParams() outside of the {Outlet}.

+1 for the PR you offered @EthanYidong

aarongreenlee avatar Jun 03 '22 00:06 aarongreenlee

@aarongreenlee I'm working on a time-sensitive project so I won't be able to work on that for the next two weeks or so. In the meantime, I've come up with a somewhat hacky solution.

https://github.com/EthanYidong/solid-app-router/tree/globalParams

I've reexported the RouteContextObj so that I can directly access the RouteContext data, which includes parent and child fields. These can be used to get the params of children of the current component, like this:

const route: any = useContext(RouteContextObj);
const slug = createMemo(() => {
  let cur = route;
  let slug = cur.params.slug;
  while(!slug && cur.child) {
    cur = cur.child;
    slug = cur.params.slug;
  }
  return slug;
});

(I'm trying to access a parameter named slug, which could be at varying depths of nesting below the current component)

I'm not sure how well traversing a "linked list" works with SolidJS's reactivity, but so far this works as expected.

EthanYidong avatar Jun 04 '22 17:06 EthanYidong

Hi! I have the same issue as you @EthanYidong.

Is there a different solution that I can use without reexporting the RouteContextObj and so changing the source?

FYI: @btakita @RobKohr @tslocke.

Thanks JBP

jBernavaPrah avatar Sep 26 '22 14:09 jBernavaPrah

Same problem encountered when trying to use useParams() in a solid-start layout The hack I used:

const location = useLocation()
const resourceId = () => location.pathname.replace('/path/to/replace/', '')

quentindutot avatar Nov 03 '22 22:11 quentindutot

Any one interested in this willing do a little leg work for me? We made a choice that seemed sensible, mostly that this decision might lead us to a path where we'd need to reactively account for things that don't exist. Ie.. have to use proxies. Seemed sort of dangerously leaky. But I'd consider it if this was pretty standard. So do other client routers allow this?

The next thing I'd be doing is looking at React Router, Tanstack Router, Next Router, Sveltekit Router, Nuxt Router, etc.. and determining if they had this functionality.

ryansolid avatar Nov 21 '22 20:11 ryansolid

I'm converting a react project to Solid and ran into this, so I can confirm React Router has this functionality.

mantissa7 avatar Jan 19 '23 16:01 mantissa7

Ok I talked to Tanner and Tanstack Router does this as well.. although it isn't documented. I'm leaning towards changing it. Anyone know about Nuxt or SvelteKit routers?

ryansolid avatar Jan 19 '23 20:01 ryansolid

I have a solution. Pretty simple but the caveat is you still can't access the params outside of the <Routes> component. This makes sense because the route definitions are not global. And I only share params within he owning <Routes>. If nested <Routes> definitions they don't get it.

The biggest impact here API-wise though is on Server Component type architectures. Using the lower route data params as a dependency for data fetching will be broken. Mostly that we would not re-run this outer layout on the server. The client islands that listen to the param would be fine and update with the data, but the data for the route itself would never refetch. I don't see this being a common case, but again neither should this. The problem is that with this setup now someone could hoist the data fetching higher and messes with being able to optimize for only the sections that change.

I'm ok with this I think. Using this feature in general is very much at your own risk. You are already listening to things that may not be there. And in no way will we not make those optimizations when the time comes and it will be broken for those who opt into it and use this to data fetch. Knowing this it is probably very unlikely Next 13 supports this as it is just giving developers footguns. Looking at Sveltekit and the way they anchor off this global page object I suspect they do support this.

So yeah I will merge.

ryansolid avatar Jan 20 '23 08:01 ryansolid