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

Next dev with React 18, Always render twice #35822

Closed
1 task done
zeakd opened this issue Apr 1, 2022 · 22 comments
Closed
1 task done

Next dev with React 18, Always render twice #35822

zeakd opened this issue Apr 1, 2022 · 22 comments
Labels
bug Issue was opened via the bug report template.

Comments

@zeakd
Copy link

zeakd commented Apr 1, 2022

Verify canary release

  • 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.2.0: Sun Nov 28 20:28:41 PST 2021; root:xnu-8019.61.5~1/RELEASE_ARM64_T6000
    Binaries:
      Node: 16.14.0
      npm: 8.5.5
      Yarn: 1.22.17
      pnpm: 6.31.0
    Relevant packages:
      next: 12.1.4
      react: 18.0.0
      react-dom: 18.0.0

What browser are you using? (if relevant)

No response

How are you deploying your application? (if relevant)

No response

Describe the Bug

Hi.
When use next dev with react 18, page always rendered twice.

// the project is just result of `create-next-app`
// pages/index.js
import { useEffect, useState } from 'react'

export default function Home() {
  console.log('render')

  const [state, setState] = useState(() => {
    console.log('state initialize');
    return 'state';
  })

  useEffect(() => {
    return () => {
      console.log('unmounted')
    }
  }, [])

  return (
    <div>
      Home
    </div>
  )
}

스크린샷 2022-04-02 오전 12 36 06

even lazy state intialize twice, and unmount last. So I think it is not remounted, but create twice.
However, next build && next start is okay and render once.

Thanks

Expected Behavior

Render, and Initialize Once with next dev

To Reproduce

  • create-next-app
  • npm run dev
@zeakd zeakd added the bug Issue was opened via the bug report template. label Apr 1, 2022
@zeakd zeakd changed the title With React 18, Always render twice Next dev with React 18, Always render twice Apr 1, 2022
@GLObus303
Copy link

GLObus303 commented Apr 1, 2022

Is it possible that you are wrapping the App in StrictMode? That would explain that double render.

I can reproduce the same double calling of the hooks in this simple demo -> https://codesandbox.io/s/late-leaf-k5qh9k?file=/components/Test.js when wrapping the App in StrictMode

This is after full page reload:
CleanShot 2022-04-01 at 18 03 24

We have just run into a similar issue with the "useUpdateEffect" construct in our Next v12 + React v18 project. Is it expected?

@michal-filip
Copy link

Confusing as it may be (it certainly is to me!) this seems to be the correct new behavior of strict mode in React 18. Effects, state initializers, renders (etc.) are called twice in dev mode when react is in strict mode.
When it comes to useEffect, what actually happens is that the effect creator is run, then the destructor is run (after which react does some assertions - forgive my ignorance here) and then state is somehow restored and effect creator is run again. In case of the custom useUpdateEffect hook, adding a destructor - which reverts the value of a ref - fixed the behavior. See the following sandbox: https://codesandbox.io/s/gifted-cannon-tgs7lv?file=/components/Test.js

@MonstraG
Copy link
Contributor

MonstraG commented Apr 1, 2022

React 18's release blogpost talks about this behavior in section New Strict Mode Behaviors

@zeakd
Copy link
Author

zeakd commented Apr 2, 2022

I think this is not correct behavior, the call order is weird.

In blog post said

This new check will automatically unmount and remount every component, whenever a component mounts for the first time, restoring the previous state on the second mount.

if it is correct strict mode behavior, it should be

  • render
  • initialize state
  • unmounted
  • render

but it's not. unmount should be called between render, and initialize state should be called once.

Initializing lazy state twice is critical part in my case. heavy object is created first twice and then destroyed last once. it is hard to organize because second creation is occured before destroy(umount). it seems to create two page component in parallel

@zeakd
Copy link
Author

zeakd commented Apr 2, 2022

Okay, I found a creation twice related issue facebook/react#20090 and it is correct to call initialize state function twice. Thank you all!
But I still wonder, why unmount is not called between render? In CRA, unmount is not even called.

@DonovanCharpin
Copy link

DonovanCharpin commented Apr 7, 2022

Same issue on my side (dev/build) with version 12.1.4. This issue only happens when using React 18.

From the React 18 upgrade guide, it seems that I cannot really fix it on my side as it is happening internally in next.

I'm using a custom express server and don't have much configuration. I can clearly see the first render (no interaction, only html etc) and the bundle render (with interaction) which is rendering just below to the first render.

It could be linked to the strict mode or a hydratation issue. I will try to change some configurations to see if I can find a fix.

@DevinEdwards
Copy link

DevinEdwards commented Apr 7, 2022

Same issue on my side (dev/build) with version 12.1.4. This issue only happens when using React 18.

From the React 18 upgrade guide, it seems that I cannot really fix it on my side as it is happening internally in next.

I'm using a custom express server and don't have much configuration. I can clearly see the first render (no interaction, only html etc) and the bundle which render just below to the first render.

It could be linked to the strict mode or an hydratation issue. I will try to change some configurations to see if I can find a fix.

Same issue here with version 12.1.4 & React 18. I am getting the initial HTML bundle on top of the rehydration. You can navigate through the rehydration, however, the initial HTML on top remains.

This is only happening on next build and we are not using Strict Mode

@yourfavorite
Copy link

I'm running into this issue too and it's breaking my current JWT refresh implementation by causing a race condition where two refresh requests are happening simultaneously. I've put in a workaround using localstorage for now but it's very strange that my authorization provider component is rendering (mounting?) twice in React 18 even though I'm not using strict mode.

@dung28-td
Copy link

It is intended in React 18 with Strict Mode (FYI: https://reactjs.org/blog/2022/03/08/react-18-upgrade-guide.html#updates-to-strict-mode). You can find a workaround here (reactwg/react-18#18)

@imaksp
Copy link
Contributor

imaksp commented Apr 13, 2022

I'm running into this issue too and it's breaking my current JWT refresh implementation by causing a race condition where two refresh requests are happening simultaneously. I've put in a workaround using localstorage for now but it's very strange that my authorization provider component is rendering (mounting?) twice in React 18 even though I'm not using strict mode.

If you are not using strict mode it should not happen, so there might be some other issue with your code, & disabling strict mode is not recommended, as it is helpful in catching errors early.

@imaksp
Copy link
Contributor

imaksp commented Apr 13, 2022

These are the logs with Strict mode ON, React 18 & latest Next.js 12.1.5, you can also see grayed out duplicate render log if you have installed React dev tools & it will confirm that its done by React strict mode
See this for more details: https://reactjs.org/blog/2022/03/08/react-18-upgrade-guide.html#other-notable-changes

react-18-strict-mode

@RigottiG
Copy link

I'm facing the same issue

@mohdashraf010897
Copy link

mohdashraf010897 commented Apr 16, 2022

@zeakd I did read about the new strict mode behavior and turns out we can avoid this by turning off the strict mode in next.config.js.

Next.js docs ref for strictMode toggling

Screenshot 2022-04-16 at 12 57 20 PM

Worked for me 😉

Additionally, you can read about what's new in the react 18 strict mode here.

@alexalannunes
Copy link

and when the app makes calls to an api, it will call 2 times. If I want to keep StrictMode will this always happen?
😢

@mohdashraf010897
Copy link

@alexalannunes Yes, but it's just a dev mode thing and doesn't affect production build 😄

@mankeheaven
Copy link

confused with 18 render twice

@sibouras
Copy link

sibouras commented Apr 26, 2022

when using strict mode in react without nextjs the console output is grayed out, why is it not in nextjs?

@VahanBeck
Copy link

This change should've been highlighted more! 😪

@imaksp
Copy link
Contributor

imaksp commented Apr 27, 2022

when using strict mode in react without nextjs the console output is grayed out, why is it not in nextjs?

Its grayed out(with react devtools) in Nextjs too, at least for me, Also getting unmount log before 2nd render. Everything is working as expected.

@sibouras
Copy link

Its grayed out(with react devtools) in Nextjs too, at least for me, Also getting unmount log before 2nd render. Everything is working as expected.

i retested it and ur right its grayed out but not inside a useEffect(idk why!)

import { useState, useEffect } from 'react';

export default function App() {
  console.log('render');

  const [state, setState] = useState(() => {
    console.log('state initialized');
    return 'state';
  });

  useEffect(() => {
    console.log('run useEffect');
    return () => console.log('unmount/ cleanup Effect');
  }, []);

  return <div>hey</div>;
}

render-gray

also the second render is before the unmount, i get the same order with react and next!

@balazsorban44
Copy link
Member

This is working as intended as pointed out by many.

Please have a look at https://reactjs.org/blog/2022/03/08/react-18-upgrade-guide.html#updates-to-strict-mode for the explanation.

@michalstrzelecki

This comment was marked as off-topic.

@vercel vercel locked and limited conversation to collaborators May 6, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug Issue was opened via the bug report template.
Projects
None yet
Development

No branches or pull requests