vercel / next.js

The React Framework
https://nextjs.org
MIT License
125.36k stars 26.78k forks source link

Make router.query available from any route, regardless of data fetching requirements. #20026

Closed acalvino4 closed 3 years ago

acalvino4 commented 3 years ago

Feature request

To access query parameters (i.e. ?author=Nick&category=lifestyle) in a page route in next.js, the appropriate method seems to be getting a router reference via the useRouter hook. However, the documentation notes that router.query "will be an empty object during prerendering if the page doesn't have data fetching requirements". Would it be possible to do away with this requirement? Is there any reason that a route without getStaticProps or getServerSideProps can't have access to these params, given that they are typically accessible from window.location? I think implementing this would improve the user experience.

Of note, the router object returned from useRouter already has access to these params in it's asPath attribute. I may be missing something, but it would seem trivial to me to have a method that loads these into the router.query object from the useRouter() call.

Describe alternatives

The alternative seems to be implementing getStaticProps or getServerSideProps, though besides this being more work than is ideal from a developer experience perspective, there aren't really instructions on how exactly this is accomplished. Does just having getStaticProps implemented then load params into router.query? Or do I need to pass context.params from getServerSideProps in as a prop? So far I haven't figured out how this alternative works either.

jamesmosier commented 3 years ago

Hi @acalvino4. There are a number of issues like this (that I can't track down right now), but I did find this answer to be descriptive of what the reasoning is: https://github.com/vercel/next.js/issues/16019#issuecomment-693712695

acalvino4 commented 3 years ago

Hi @jamesmosier, thank you for pointing me to that discussion.

I'm still a little confused, as this paragraph from that discussion:

Now let's say every single one of your visitors uses a different query param. What's happening in that case is that we will continue to serve the same exact html page (that didn't know anything about the query params when it was created) and once the JS executes in the browser you can start making dynamic changes to the page. That's why there's no way to know your query params unless the page is generated per-request

implies to me that while at initial load the query params are of course unknown, that useRouter could still have client side code that is executed to read in the query params and update the page from there - is that correct?

timneutkens commented 3 years ago

implies to me that while at initial load the query params are of course unknown, that useRouter could still have client side code that is executed to read in the query params and update the page from there - is that correct?

But only after hydration https://reactjs.org/docs/react-dom.html#hydrate as otherwise the html content does not match up with the client-side hydration React tree and React will throw away all the pre-rendered content causing performance issues. If you don't have getStaticProps or getServerSideProps Next.js will automatically statically generate the page, meaning the HTML does not change after build.

When a hydration mismatch happens it causes UI jumps which is worse for user experience.

I'll close this issue as there's multiple others already like #8259

hexetia commented 3 years ago

@acalvino4 I just published a package with a workaround

It's a tiny package that wrap the next.js router to provide the router.query and router.pathname on client-side first render

https://www.npmjs.com/package/use-client-router

timneutkens commented 3 years ago

@morhogg as said in https://github.com/vercel/next.js/issues/20026#issuecomment-743747064 providing it is not the way to go and will cause performance issues and jumps in your application.

acalvino4 commented 3 years ago

@timneutkens @jamesmosier There are a few points in my original post that were not really answered yet.

  1. "the router object returned from useRouter already has access to these params in it's asPath attribute. I may be missing something, but it would seem trivial to me to have a method that loads these into the router.query object from the useRouter() call." - Why is this not possible?
  2. Ultimately, I do trust your judgement as someone familiar with the codebase, so I am interested in best practice workarounds. If it really is impossible to ever implement this feature, then we can refocus the discussion to a request to have more clear documentation about the alternative. In my original post I described what is lacking in the documentation currently.
balazsorban44 commented 2 years ago

This issue has been automatically locked due to no recent activity. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.