Fixing Next.js router query param returning undefined on initial render

While building a React application using next.js, I stumbled upon an issue that kept me stuck for a good amount of time. I don't want people to do the same therefore I would be covering the fix in this blog. Feel free to skip to fix if you want to.

Issue

First, let's just try to reproduce this issue. You might encounter some cases where you need access to query params of a route. Nextjs makes it easy to deal with routes by using the useRouter hook. Here's an example code that you can place inside the /pages directory to try it out.

import { useRouter } from 'next/router';
import React from 'react';

const Test = () => {
  const router = useRouter();
  console.log(router.query);
  return <div>Hello World</div>;
};

export default Test;

Now let's visit the router with some param and see the logs. In my case, I visited /test?name=Deepankar.

{}
{name: 'Deepankar'}

As you can see in the 1st render we don't have the access to the param. So how do we know when the router fields are updated client-side and ready for use?. Now let's look into the fix.

Fix

useRouter hook returns isReady field which is a boolean value that denotes if the router fields are updated client-side and ready for use. Accessing isReady field should be done inside of useEffect methods and not for conditionally rendering on the server.

import { useRouter } from 'next/router';
import React from 'react';

const Test = () => {
  const router = useRouter();
  React.useEffect(() => {
    if (router.isReady) {
      // Code using query
      console.log(router.query);
    }
  }, [router.isReady]);
  return <div>Hello World</div>;
};

export default Test;

Reason

Pages that are statically optimized by Automatic Static Optimization will be hydrated without their route parameters provided, i.e query will be an empty object ({}).

After hydration, Next.js will trigger an update to your application to provide the route parameters in the query object.

References:

29