Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: 6.0.0-beta.5 lost parent params in nested route #8073

Closed
otakustay opened this issue Sep 26, 2021 · 9 comments
Closed

[Bug]: 6.0.0-beta.5 lost parent params in nested route #8073

otakustay opened this issue Sep 26, 2021 · 9 comments

Comments

@otakustay
Copy link

What version of React Router are you using?

6.0.0-beta.5

Steps to Reproduce

  1. Open https://codesandbox.io/s/admiring-minsky-k8clw?file=/src/App.js
  2. Click "Render View" link
  3. Check params rendered in page

Expected Behavior

It should render {type, id}, with type as its parent route params and id of its own

Actual Behavior

It renders {id}, type param is lost

@benweier
Copy link

Same bug appears to be causing issues for me on beta.5 Getting a "no routes matched location" console warning for a nested route that worked perfectly on beta.4. Only difference is no route params, just static routes

@lucasvienna
Copy link

We've had a similar issue after updating. The route structure is as follows;

<Route path="/view">
  <Route
    path={`typeA/*`}
    element={<Layout type="a" />}
  />
  <Route
    path={`typeB/*`}
    element={<Layout type="b" />}
  />
</Route>

and the layout component then has a few subroutes:

<Routes>
  <Route
    path={`subrouteA/:paramY/*`}
    element={<... />}
  />
  <Route
    path={`subrouteB/:paramY/*`}
    element={<... />}
  />
  <Route
    path="*"
    element={<Empty />}
  />
</Routes>

What seems to be happening is that the upper * gobbles up the first part of the nested route (the subrouteX part), and the nested catch-all (that renders <Empty />) then identifies the paramY part alone, spitting back { *: 'paramY' } when useParams is called in that route.

@svenheden
Copy link
Contributor

We've encountered the same bug, in 6.0.0-beta.5

@mjackson
Copy link
Member

It renders {id}, type param is lost

@otakustay This was an intentional breaking change in beta.5. Sorry I forgot to put it in the release notes for beta.5. I just added them.

The rationale is that we want to align useParams() more closely with the params you see in a given set of <Routes>. When you call useParams() in any route, you get the params available to that set of <Routes>. This should make it easier to predict which params you'll get back from useParams() and also makes it easier to avoid param name collisions with ancestor <Routes> elements that you (probably) can't see in the same file.

If you need the params from a parent set of <Routes>, we recommend you pass them along to the components that need them as props. I forked your codesandbox to show you how this is done.

You could also ofc create your own context object and merge all the params for your whole app together using whatever logic you'd like. In this case, it's your responsibility to make sure there are no param name collisions and that you always render your <Routes> inside ancestor <Routes> that have the params they need.

const AllParamsContext = React.createContext({});

function AllParamsProvider({ children }) {
  return <AllParamsContext.Provider value={useAllParams()} children={children} />;
}

function useAllParams() {
  return {
    // capture the params from all parent <Routes>
    ...React.useContext(AllParamsContext),
    // capture the params from this <Routes>
    ...useParams()
  };
}

function TopRoutes() {
  return (
    <AllParamsProvider>
      <Routes>
        <Route path=":type/*" element={<TypeRoute />} />
      </Routes>
    </AllParamsProvider>
  );
}

function TypeRoute() {
  return (
    <AllParamsProvider>
      <Routes>
        <Route path=":id" element={<Page />} />
      </Routes>
    </AllParamsProvider>
  );
}

function Page() {
  let params = useAllParams();
  // ...
}

@Avyiel It sounds like you may have a related problem, but it has to do with splat routes instead of params. Maybe check #8074?

@eshy
Copy link

eshy commented Sep 30, 2021

This change is a bad design.

Being able to easily access parent route params make it simple to split route definitions.
Removing that option requires passing parameters down to children, multiple levels in some cases.

The stated goal in the release notes states this is to make components with Routes portable but if you need that, just don't use parent params.
Let me make that choice when I'm building my app instead of forcing me to pass parameters down.

I have a feeling this solution is for a less used scenario as well.

@svenheden
Copy link
Contributor

This change is a bad design.

Being able to easily access parent route params make it simple to split route definitions. Removing that option requires passing parameters down to children, multiple levels in some cases.

The stated goal in the release notes states this is to make components with Routes portable but if you need that, just don't use parent params. Let me make that choice when I'm building my app instead of forcing me to pass parameters down.

I have a feeling this solution is for a less used scenario as well.

I strongly agree with this, and was surprised when I read @mjackson's reply that this is intentional. From my experience it's a very common use case to want to read parent route params, and to no longer have support for this in the router itself feels less than ideal.

@mjackson
Copy link
Member

mjackson commented Oct 2, 2021

It's ok to disagree with our design decisions. But when I give you our rationale, and a complete workaround to preserve the old behavior if you really want it, I'd appreciate a little more thoughtful response than "this is bad design".

In general we favor explicit over implicit code. Getting params from some distant ancestor <Routes> definitely falls into the implicit category and makes it a lot easier to write hard-to-find bugs. So this change just makes the code a lot more explicit and easier to read and follow.

Locking this thread to prevent more piling on.

@remix-run remix-run locked as resolved and limited conversation to collaborators Oct 2, 2021
@mjackson mjackson reopened this Oct 4, 2021
@mjackson
Copy link
Member

mjackson commented Oct 4, 2021

We decided that this feature won't mess up our future plans for the router, so I'm going to add it back. Thanks for your patience and for bringing this to our attention.

mjackson added a commit that referenced this issue Oct 5, 2021
@mjackson
Copy link
Member

mjackson commented Oct 7, 2021

This was added back in 16214b2 and will be released today in beta.6

@mjackson mjackson closed this as completed Oct 7, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants