Rendering content based off Next.js router.query causes re-render and flicker?

Viewed 1261

I have a page that uses router.query to determine what content to render.

However, it looks like the page will always render without router.query first before loading the router.query code in resulting in the page "flickering"

Here is a simple stackblitz to show what I mean: https://stackblitz.com/edit/nextjs-jvtyrm?file=pages/index.js

Relevant code bits:

export default function Home() {
  const router = useRouter();
  const isRouterQuery = router.query.foo ? true : false;

  return (
    <div className={styles.container}>
      <main className={styles.main}>
        <button
          onClick={() => {
            if (isRouterQuery) {
              window.location.href = '/';
            } else {
              window.location.href = '/?foo=bar';
            }
          }}
        >
          Toggle between homepage and homepage with router.query
        </button>
        {isRouterQuery ? (
          <h1 className={styles.title}>Router Header</h1>
        ) : (
          <h1 className={styles.title}>
            Welcome to <a href="https://nextjs.org">Next.js!</a>
          </h1>
        )}

// ...

If you click the button to toggle from / to /?foo=bar, you'll see that the initial render shows Welcome to Next.js for a split second before re-rendering to show the Router Header content.

How do I get rid of this initial flicker?

1 Answers

If a page does not have data fetching methods, the flicker will always occur on the page's first load because when the page gets pre-generated on the server by Next.js router.query is an empty object.

From the next/router documentation:

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 {}

In your case, you're also experiencing the flicker when clicking the button because you use window.location.href to navigate between pages, and that causes a full page reload rather than a client-side navigation.

To fix the issue, just replace the window.location.href statements with router.push calls. This way Next.js can properly execute a client-side navigation, which does not trigger the flickering.

<button
    onClick={() => {
        if (isRouterQuery) {
            router.push('/');
        } else {
            router.push('/?foo=bar');
        }
    }}
>
    Toggle between homepage and homepage with router.query
</button>
Related