next.js
next.js copied to clipboard
Next.js router.isReady never set to true on custom 404 page
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:
-
Router is not ready
on the first render -
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:
-
Router is not ready
on the first render - ...there will not be a second render at all
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.
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...
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
I found out that router.isReady
works as expected when reusing the built-in error by creating custom _error
page.
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.
@vixeven @Saturate, I also facing this problem, could you share or explain how to reuse the built-in error page
to solve this? Thanks!
@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
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.