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

Make router API consistent #16019

Closed
mehulmpt opened this issue Aug 9, 2020 · 2 comments
Closed

Make router API consistent #16019

mehulmpt opened this issue Aug 9, 2020 · 2 comments
Labels
please add a complete reproduction Please add a complete reproduction.

Comments

@mehulmpt
Copy link

mehulmpt commented Aug 9, 2020

Bug report

Describe the bug

Currently, the useRouter hook gives the router object which can be used to access dynamic parts of the URL (like [slug] or [postid] in the URL). However, this is only possible IF we use getServerSideProps (even if it means I'm doing no work in that function, the next.js router would NOT populate the query object if getServerSideProps is not known)

Straight from the docs: ( https://nextjs.org/docs/api-reference/next/router )

query: Object - The query string parsed to an object. It will be an empty object during prerendering if the page doesn't have data fetching requirements. Defaults to {}

I manage this problem by having a custom function which explodes the URL path and extracts the path manually on the client. But this creates another problem.

This creates a problem when you want to have static pages created by Next.js, but want to use dynamic parts of URL, in some component, say the Link component from next/link because now the server and client's React tree differ. Because on the server, you cannot query the real location as all you get from the useRouter hook is in some form of placeholder:

{
  route: '/class-manager/[slug]/manage/[labslug]',
  pathname: '/class-manager/[slug]/manage/[labslug]',
  query: {},
  asPath: '/class-manager/[slug]/manage/[labslug]',
  basePath: '',
  events: undefined,
  isFallback: false
}

Because of this, we cannot populate the correct as attribute of the Link component hence it results in a React tree mismatch between client and server, and the following error appears:

Warning: Prop href did not match. Server: "/class-manager/undefined/manage/undefined/edit" Client: "/class-manager/d914e7b6-5405-4f8e-8c54-ea85a18ac697/manage/84cf2da6-633b-4e21-a434-d9acde214c95/edit"

This is expected, because we don't have real URL access when Next.js is trying to pre-render the page. However, this is a huge problem if somebody visits this dynamic URL directly (not from a page navigation, but a visit directly) because in that case React gives the server rendered code precedence over what client has to say, which results in the following button:

Screenshot 2020-08-09 at 7 23 19 PM

See the path on bottom left of white screen - they're both undefined even though they are available on client. To fix this, wherever we're using dynamic route and are not fetching static data from Next methods, we're rendering the Link component dynamically only on the client

import dynamic from 'next/dynamic'
const Link = dynamic(() => import('next/link'), { ssr: false })

which is of course not a nice solution because it results in a little flash while the component is loading. I'm sure there's a better way to internally fix this issue with the router API to make sure the complete URL and query object is available even without server side rendering or static prop requirements?

Just wanted to put this out and know what you think. Thanks!

@lfades
Copy link
Member

lfades commented Sep 16, 2020

Closing due to my comment in #9473 (comment).

The issue you're describing here is not an issue, is the way static content works.

This is expected, because we don't have real URL access when Next.js is trying to pre-render the page. However, this is a huge problem if somebody visits this dynamic URL directly (not from a page navigation, but a visit directly) because in that case React gives the server rendered code precedence over what client has to say

It's expected and it's not going to change. We don't give precedence to the server rendered code. We first render the HTML that was generated in Node.js (aka server) at build time, and then hydrate the page with dynamic data (like query params) once the js code executes in the browser.

Using an example, if we have pages/home.js, in Node.js we will build a home.html that can be served to all of your visitors. If you have 10k visitors going to /home they will receive the same home.html that was generated before, that should be very fast because you're not generating any content per-request.

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

@balazsorban44
Copy link
Member

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.

@vercel vercel locked as resolved and limited conversation to collaborators Jan 29, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
please add a complete reproduction Please add a complete reproduction.
Projects
None yet
Development

No branches or pull requests

4 participants