next.js icon indicating copy to clipboard operation
next.js copied to clipboard

Next.js router.isReady never set to true on custom 404 page

Open iiroj opened this issue 2 years ago • 7 comments

Verify canary release

  • [X] I verified that the issue exists in Next.js canary release

Provide environment information

Operating System:
      Platform: darwin
      Arch: arm64
      Version: Darwin Kernel Version 21.4.0: Fri Mar 18 00:46:32 PDT 2022; root:xnu-8020.101.4~15/RELEASE_ARM64_T6000
    Binaries:
      Node: 17.7.2
      npm: 8.5.5
      Yarn: 1.22.17
      pnpm: N/A
    Relevant packages:
      next: 12.1.5-canary.4
      react: 17.0.2
      react-dom: 17.0.2

What browser are you using? (if relevant)

Safari 15.4 (17613.1.17.1.13)

How are you deploying your application? (if relevant)

next dev

Describe the Bug

The Next.js router object contains a boolean value router.isReady, which according to docs indicates:

Whether the router fields are updated client-side and ready for use. Should only be used inside of useEffect methods and not for conditionally rendering on the server. See related docs for use case with automatically statically optimized pages

We are using this in a withSSRLoadingIndicator HoC that checks inside an useEffect hook that if the router is ready, render page component, and else render a full-screen loading indicator. This allows us to deploy certain pages as small static files, which only load client-side, while other pages can use the full getServerSideProps method and render what they need directly. With the HoC, we don't have to check if the router.query object is populated, because the page component will receive the data on its first render (because then router.isReady = true).

This HoC works nicely on all other pages expect our custom 404 page, and after a bit of debugging it seems that the Router instance simply never sets router.isReady = true.

Expected Behavior

I would expect the custom 404 to also receive router.isReady = true on the client-side.

To Reproduce

Create a Next.js page src/pages/index.js with code like this:

import { useRouter } from 'next/router'
import React, { useEffect, useState } from 'react'

export default () => {
  const router = useRouter()
  const [state, setState] = useState(false)

  useEffect(() => {
    setState(router.isReady)
  }, [router.isReady])

  return <p>{state === true ? 'Router is ready' : 'Router is not ready'}</p>
}

When opening the page in your browser, http://localhost:3000/, you will see:

  1. Router is not ready on the first render
  2. Router is ready on the second render

Copy the same page component as src/pages/404.js, open http://localhost:3000/404, and you will instead see:

  1. Router is not ready on the first render
  2. ...there will not be a second render at all

iiroj avatar Apr 08 '22 08:04 iiroj

Additionally, after landing on a 404 page the isReady value remains false for the lifetime of the router. If you land on a custom 404 page that doesn't use router.isReady but then use the site nav to navigate to a different page that does, the page following that client side navigation will break.

bryanrsmith avatar Apr 13 '22 15:04 bryanrsmith

I had the same issue because router.replace (shallow) was executed during the first render. I moved it inside a useEffect and it fixed my problem. If it can be of any help to debug...

cvolant avatar Jun 21 '22 10:06 cvolant

I am able to reproduce this bug the way @iiroj described. Do we have any progress on this bug? It hardly breaks my website's functionality

mykyta-hryn avatar Aug 17 '22 15:08 mykyta-hryn

I found out that router.isReady works as expected when reusing the built-in error by creating custom _error page.

vixeven avatar Sep 01 '22 11:09 vixeven

I found out that router.isReady works as expected when reusing the built-in error by creating custom _error page.

I can confirm this works, I needed access to router.query and had troubles doing this on a 404 page.

Saturate avatar Oct 04 '22 07:10 Saturate

@vixeven @Saturate, I also facing this problem, could you share or explain how to reuse the built-in error page to solve this? Thanks!

qiweiii avatar Oct 26 '22 14:10 qiweiii

@vixeven https://github.com/vercel/next.js/issues/35990#issuecomment-1234138381 links to it :) But here you go: https://nextjs.org/docs/advanced-features/custom-error-page#reusing-the-built-in-error-page

Saturate avatar Oct 27 '22 12:10 Saturate

This closed issue has been automatically locked because it had no new activity for a month. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.

github-actions[bot] avatar Jan 12 '23 12:01 github-actions[bot]