-
Notifications
You must be signed in to change notification settings - Fork 27.2k
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
Add a ready: boolean
to Router
returned by useRouter
#8259
Comments
You can either keep all the changes that depend in the query params inside |
We can't use
I wish that was true... but it isn't. Besides For now we have a workaround that looks like the following, but ideally, I'd prefer import NextRouter, {
useRouter as useNextRouter,
NextRouter,
} from 'next/router';
const RouterContext = React.createContext<NextRouter & { ready: boolean }>(
null as any,
);
export function RouterContextProvider({
children,
}: {
children?: React.ReactNode;
}) {
const router = useNextRouter();
// In order to know if the params that are passed by router
// are actually correct
// (because sometimes on initial render they might be equal to server-side params,
// not the ones that are currently visible in the browser),
// we'll be relying on this `ready: boolean` property.
// ( Workaround until next.js give us a proper solution for it
// - see https://github.com/zeit/next.js/issues/8259 )
const [ready, setReady] = useState(false);
useEffect(() => {
const timeout = setTimeout(() => {
setReady(true);
});
return () => clearTimeout(timeout);
}, []);
const wrappedRouter = useMemo(
() => ({
...router,
ready,
}),
[router, ready],
);
return (
<RouterContext.Provider value={wrappedRouter}>
{children}
</RouterContext.Provider>
);
}
export function useRouter() {
return useContext(RouterContext);
} |
Sorry, but you cannot branch rendering logic based on booleans -- this causes hydration mismatches and typically indicates a code pattern that needs fixed.
You can rely directly on Also, this If you provide a full example of your exact use case, we may be able to suggest a better React pattern. |
Yeah, but RouterContext is updated once I want to avoid branching rendering logic based on "am I on ssr?" booleans to make hydration work, thus raised this issue.
We have routes with dynamic parameters. Parsing |
Our example is like this:
So basically, we need to be able get the initial route params on/after the page loads, and then act on it (i.e. show an error to the user if the params are incorrect). However, currently, without the above workaround, if we navigated to the
If we won't rely on sth like We'd like to avoid having weird workarounds like surrounding the "show error code" with |
Hiya I ended up putting the query into state:
This cause multiples render cycles, but I do not see any other way of getting the router params. I am using a Static build, so do not want to use getInitial... be great if examples could showcase static methods also to state best practices. |
+1 for better documentation around static patterns. |
I was having exactly the same problem - I solved it the following way: @jtomaszewski you can have something like this: import { NextRouter } from 'next/router';
export function isRouterReady(router: NextRouter) {
return router.asPath !== router.route;
} If you are using pre-rendered pages, immediately after hydration the router.route property and router.asPath property will have exactly the same value. In your case, in the first render you'll have:
In the second render you'll have something like:
So in your component you can do: export function MyComponent() {
const router = useRouter();
useEffect(() => {
if (isRouterReady(router)) {
// here you have your query params
}
}, [router]);
} @Timer can you confirm if this is a valid approach? |
Upon further thought, I don't see the harm in supporting |
I ran into a similar issue where I am using the
It is rather confusing in these instances, where hooks should be compostable in custom hooks, that |
@Soundvessel In the case of prerendered pages (pages without I agree that docs don't currently do a good job explaining it, but it will get fixed soon 👍 |
Ah and I think a ref is a good way to set something in that Here is my now working updated hook.
|
What is rather weird is that I made a custom hook since I needed to use the query in several other components. For some reason the above works but when I switch to it using this hook which uses the same code I get the stale query again. Looks like the useEffect needs to exist where you are using the query and can't be from a custom hook?
|
This only works if you expect query params to be populated. IE, if there were NO query params to be added, then this would never return true, which is a bug. I think the only clean way to "know" at least from client code, is to have the query params in the |
…lue is populated. fix vercel#8259
Made a PR that adds a new parameter called const { query, isReady } = useRouter(); where I HAD to use something that wasn't type SingletonRouterBase = {
router: Router | null
readyCallbacks: Array<() => any>
ready(cb: () => any): void
} After speaking with the maintainers, we decided on |
…lue is populated. fix vercel#8259
I'm seeing multiple rendering issue only with dynamic routes. This seems to work:
|
Running into this issue also. From my ignorant next internals perspective it seems strange that I'm using similar to @bmvantunes's approach for now: const isDynamicPage = (router) => /\[.+\]/.test(router.route);
const testRouterReady = (router) => !isDynamicPage(router) || router.asPath !== router.route; |
This comment has been minimized.
This comment has been minimized.
Facing the same problem I tried to use
|
I have faced the same problem and 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 |
This will very likely cause hydration mismatches causing React to throw away the pre-rendered HTML causing performance issues and jumps/issues with the pre-rendered HTML. |
My query params are still not showing up in production when |
This could be a good solution: https://github.com/morhogg/use-client-router |
@jackguoAtJogg it'll break hydration causing pages to get into a broken state so certainly would not recommend it. |
As a workaround, I created a pageQuery hook that parses the utm params manually and appends them to
|
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. |
Because of the way Next.js does initial render of the pages, and that the initial render on client-side and server-side has to be the same (see https://reactjs.org/docs/react-dom.html#hydrate ), sometimes when a page is rendered, its'
query
(returned i.e. byuseRouter()
hook) will be empty, even though it actually has query params. After the initial render, soon after there will be another render in which thequery
will be then populated with proper query params. ( Example described also in i.e. #7880 )My code relies on those query params very heavily and we need to know "are those the real current query params or not yet?". (i.e. because if query params are missing or incorrect, we'd like to redirect the user to another page)
Describe the solution you'd like
I think that either:
query
should be always populated with the current query params (even on initial client-side hydration that happens after a server-side render)ready: boolean
flag toRouter
, so the component can listen to this using i.e.useEffect
and ignore the query params when they aren't parsed yet.Describe alternatives you've considered
I think we'll have to go with some
setTimeout
or sth for now until a better solution is found.The text was updated successfully, but these errors were encountered: