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

router.asPath different between server and front on 404 page

Open Poyoman39 opened this issue 3 years ago • 1 comments

Verify canary release

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

Provide environment information

Operating System:
  Platform: linux
  Arch: x64
  Version: #1 SMP PREEMPT Mon Sep 5 10:15:47 UTC 2022
Binaries:
  Node: 16.16.0
  npm: 8.19.1
  Yarn: N/A
  pnpm: N/A
Relevant packages:
  next: 12.3.1-canary.2
  eslint-config-next: 12.3.0
  react: 18.2.0
  react-dom: 18.2.0

What browser are you using? (if relevant)

Firefox developer edition 105.0b4 (64 bits)

How are you deploying your application? (if relevant)

No response

Describe the Bug

When accessing /someUnknownUrl

const router = useRouter();
console.log(router.asPath); // '/404' on server '/someUnknownUrl' on browser

useRouter does not work consistently between browser and server on 404 page.

Expected Behavior

router.asPath should be '/someUnknownUrl' on server too

Link to reproduction

https://stackblitz.com/edit/vercel-next-js-ycc47c?file=pages/404.tsx

To Reproduce

Go to an unknownUrl (https://vercel-next-js-ycc47c--3000.local-corp.webcontainer.io/unknownUrl)

You can see "Error: Text content does not match server-rendered HTML" caused by different rendering

Poyoman39 avatar Sep 16 '22 16:09 Poyoman39

Isn't this an expected behavior as stated here?

While rendering your application, there was a difference between the React tree that was pre-rendered (SSR/SSG) and the React tree that rendered during the first render in the Browser.

It was pre-rendered with 404 on the server but it changed to the current slug on the first render. The error is easily resolved when you apply the stated fix.

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

const Custom404 = () => {
  const router = useRouter();
  const [slug, setSlug] = useState<string>();

  useEffect(() => {
    setSlug(router.asPath.substr(1).replace(/([A-Z])/g, ' $1'));
  }, [router]);

  return <main>{slug}</main>;
};

export default Custom404;

ShaneMaglangit avatar Sep 16 '22 21:09 ShaneMaglangit

But router.asPath should return the same thing on server and client no ?

Thank you for your quickfix anyway ;)

Poyoman39 avatar Sep 23 '22 14:09 Poyoman39

If router.asPath is intended to return different content on server and on client this is not a bug then ... ;)

Poyoman39 avatar Sep 23 '22 14:09 Poyoman39

If router.asPath is intended to return different content on server and on client this is not a bug then ... ;)

I believe it is more of a side effect of pre-rendering rather than an intended effect. During pre-rendering inside the server, the router is unaware of the domain where it will be sent. It assumes its at /404 based on the filename, but it doesn't actually exists in a browser yet (its in the server, a server does not have a URL/web address).

ShaneMaglangit avatar Sep 24 '22 01:09 ShaneMaglangit