Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"Rendered more hooks than during previous render" when using router.replace #63121

Open
mynameisankit opened this issue Mar 11, 2024 · 7 comments
Labels
bug Issue was opened via the bug report template.

Comments

@mynameisankit
Copy link

mynameisankit commented Mar 11, 2024

Link to the code that reproduces this issue

Link

To Reproduce

  1. Start the application on port 3000
  2. Goto <base-url>/versions/v1
  3. Wait for a few seconds till the error screen is displayed
  4. Click on Goto Version v2

Current vs. Expected behavior

I expected to be redirected to <base-url>/versions/v2 but instead a client-side react error is triggered with the following stack trace

Uncaught Error: Rendered more hooks than during the previous render.
    at updateWorkInProgressHook (react-dom.development.js:11337:1)
    at updateMemo (react-dom.development.js:12470:1)
    at Object.useMemo (react-dom.development.js:13417:1)
    at useMemo (react.development.js:1777:1)
    at Router (app-router.js:215:58)
    at renderWithHooks (react-dom.development.js:11021:1)
    at updateFunctionComponent (react-dom.development.js:16184:1)
    at beginWork$1 (react-dom.development.js:18396:1)
    at HTMLUnknownElement.callCallback (react-dom.development.js:20498:1)
    at Object.invokeGuardedCallbackImpl (react-dom.development.js:20547:1)
    at invokeGuardedCallback (react-dom.development.js:20622:1)
    at beginWork (react-dom.development.js:26813:1)
    at performUnitOfWork (react-dom.development.js:25637:1)
    at workLoopSync (react-dom.development.js:25353:1)
    at renderRootSync (react-dom.development.js:25308:1)
    at recoverFromConcurrentError (react-dom.development.js:24525:1)
    at performConcurrentWorkOnRoot (react-dom.development.js:24470:1)
    at workLoop (scheduler.development.js:256:1)
    at flushWork (scheduler.development.js:225:1)
    at MessagePort.performWorkUntilDeadline (scheduler.development.js:534:1)

Provide environment information

Operating System:
  Platform: linux
  Arch: x64
  Version: #1 SMP PREEMPT_DYNAMIC Sun Aug  6 20:05:33 UTC 2023
Binaries:
  Node: 20.11.0
  npm: 10.2.4
  Yarn: 1.22.19
  pnpm: 8.15.1
Relevant Packages:
  next: 14.1.0
  eslint-config-next: 14.1.0
  react: 18.2.0
  react-dom: 18.2.0
  typescript: 5.3.3
Next.js Config:
  output: N/A

Which area(s) are affected? (Select all that apply)

App Router

Which stage(s) are affected? (Select all that apply)

next dev (local), next build (local), next start (local), Vercel (Deployed), Other (Deployed)

Additional context

I tested my reproduction on the following versions:-

  1. 13.4.19
  2. 14.1.0
@mynameisankit mynameisankit added the bug Issue was opened via the bug report template. label Mar 11, 2024
@mynameisankit mynameisankit changed the title "Rendered more hooks than during previous render" when Redirect "Rendered more hooks than during previous render" when using Router.replace Mar 11, 2024
@mynameisankit mynameisankit changed the title "Rendered more hooks than during previous render" when using Router.replace "Rendered more hooks than during previous render" when using router.replace Mar 12, 2024
@sirajtahra
Copy link

sirajtahra commented Jun 4, 2024

+1

@lifeisegg123
Copy link

I have dig into this issue and found that call of useThenable inside of use hook doesn't seem to work properly.
So, I tried change the implementation of useUnwrapState like this in my local machine, it worked.

function useUnwrapState(_state: ReducerState): AppRouterState {
  const [state, setState] = useState(_state);
  useEffect(()=>{
     if (isThenable(_state)) {
       _state.then(setState);
    } else {
      setState(_state)
    }
  }, [_state])

  return state
}

Maybe is it related to use hook and startTransition issue?

@jetaggart
Copy link

jetaggart commented Jul 19, 2024

We're seeing this with a component that renders nothing and only redirects where another component is calling router.replace. Probably not the best code but still feels like we shouldn't see a varying amount of hooks rendering.

export default function OnboardingCheckComplete({
  onboardingStatus,
}: {
  onboardingStatus: OnboardingStatus
}) {
  const router = useRouter()
  const pathname = usePathname()

  useEffect(() => {
    if (
      pathname !== "/onboarding/welcome" &&
      onboardingStatus.onboarding.currentStep === OnboardingStatusComplete
    ) {
      router.replace("/onboarding/welcome")
      router.refresh()
    }
  }, [pathname, onboardingStatus.onboarding.currentStep, router])

}

And the page at /onboarding

export default async function OnboardingPage() {
   const status = await gateway.onboarding.status.get()

  if (status.onboarding.currentStep === OnboardingStatusNotStarted) {
    redirect("/onboarding/start")
  } else {
    throw new Error(
      `Invalid onboarding status ${status.onboarding.currentStep}`
    )
  }
}

@hunghuy201280

This comment has been minimized.

@himself65
Copy link
Contributor

My error stack here

(anonymous) @ react-dom-client.production.js:11023
x @ scheduler.production.js:151
error-boundary-callbacks.ts:56 Error: Minified React error #310; visit https://react.dev/errors/310 for the full message or use the non-minified dev environment for full errors and additional helpful warnings.
    at lQ (react-dom-client.production.js:3494:1)
    at Object.aw [as useMemo] (react-dom-client.production.js:4161:1)
    at react.production.js:515:1
    at M (app-router.tsx:252:38)
    at lM (react-dom-client.production.js:3373:1)
    at oh (react-dom-client.production.js:6016:1)
    at o_ (react-dom-client.production.js:7012:1)
    at ic (react-dom-client.production.js:10829:1)
    at react-dom-client.production.js:10710:35
    at is (react-dom-client.production.js:10711:1)
    at u9 (react-dom-client.production.js:10289:1)
    at ij (react-dom-client.production.js:11606:1)
    at MessagePort.x (scheduler.production.js:151:1)
overrideMethod @ hook.js:608
(anonymous) @ console.js:36
s @ error-boundary-callbacks.ts:56
ot @ react-dom-client.production.js:5580
e.callback @ react-dom-client.production.js:5613
rC @ react-dom-client.production.js:2818
rz @ react-dom-client.production.js:2828
oO @ react-dom-client.production.js:7472
oK @ react-dom-client.production.js:7834
o6 @ react-dom-client.production.js:8678
oK @ react-dom-client.production.js:7802
o6 @ react-dom-client.production.js:8678
oK @ react-dom-client.production.js:7802
o6 @ react-dom-client.production.js:8678
oK @ react-dom-client.production.js:7802
o6 @ react-dom-client.production.js:8678
oK @ react-dom-client.production.js:7802
o6 @ react-dom-client.production.js:8678
oK @ react-dom-client.production.js:7868
o6 @ react-dom-client.production.js:8678
oK @ react-dom-client.production.js:7868
o6 @ react-dom-client.production.js:8678
oK @ react-dom-client.production.js:7838
iv @ react-dom-client.production.js:11190
ig @ react-dom-client.production.js:11050
u7 @ react-dom-client.production.js:10462
u9 @ react-dom-client.production.js:10387
ij @ react-dom-client.production.js:11606
x @ scheduler.production.js:151

@himself65
Copy link
Contributor

/**
 * The global router that wraps the application components.
 */
function Router({
  actionQueue,
  assetPrefix,
}: {
  actionQueue: AppRouterActionQueue
  assetPrefix: string
}) {
  const [state, dispatch] = useReducer(actionQueue)
  const { canonicalUrl } = useUnwrapState(state)
  // Add memoized pathname/query for useSearchParams and usePathname.
  const { searchParams, pathname } = useMemo(() => { // <-- this line
    const url = new URL(
      canonicalUrl,
      typeof window === 'undefined' ? 'http://n' : window.location.href
    )

    return {
      // This is turned into a readonly class in `useSearchParams`
      searchParams: url.searchParams,
      pathname: hasBasePath(url.pathname)
        ? removeBasePath(url.pathname)
        : url.pathname,
    }
  }, [canonicalUrl])

@sam-masscreations
Copy link

@himself65 did you solve this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Issue was opened via the bug report template.
Projects
None yet
Development

No branches or pull requests

7 participants