Skip to content

Concurrent mode renders components twice with different identities #17786

Closed
@sschultze

Description

@sschultze

Do you want to request a feature or report a bug?

Bug

What is the current behavior?

If concurrent mode is enabled, React renders functional components twice and (what's worse) with different identities under certain circumstances. The source code below always produces the bug.

If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem.

let instanceId = 0;

const MyFunctionalComponent = (props: any) => {
    console.log('Instance ' + useRef(instanceId++).current);
    return <h1>Hello world.</h1>;
};

const rootElement = document.getElementById('root');

(ReactDOM as any).createRoot(rootElement).render(<MyFunctionalComponent />);

// Doesn't produce the bug:
// ReactDOM.render(<MyFunctionalComponent />, rootElement);

Output:

Instance 0
Instance 1

What is the expected behavior?

One or more lines "Instance 0" in the console log. (Better: One single line "Instance 0".)

Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?

0.0.0-experimental-f42431abe

Additional notes

The bug also happens deep in the component tree and can cause costly operations to be performed twice. (In my case, those operations are done asynchronously in a class instance memorized via useRef.)

Activity

gaearon

gaearon commented on Jan 6, 2020

@gaearon
Collaborator

This is not a bug. And you'll have the same behavior in Strict Mode too. We intentionally double-call render-phase lifecycles in development only (and function components using Hooks) to help people find issues caused by side effects in render. In our experience, them firing twice is enough for people to notice and fix such bugs.

If component output is always a function of props and state (and not outer scope variables, like in your example), the double rendering in development should have no observable effect.

sschultze

sschultze commented on Jan 6, 2020

@sschultze
Author

Thank you! This makes sense.

ykforerlang

ykforerlang commented on Mar 26, 2020

@ykforerlang

very cool

ecnatsiDehTog

ecnatsiDehTog commented on Feb 18, 2021

@ecnatsiDehTog

Why did console.log be disabled when the second call of the function Component??
const App=()=>{ debbugger; console.log('App'); return null }
my App stop on the debugger twice,But in the second time,console.log won‘t print anything in the Chrome Browser Console。

gaearon

gaearon commented on Feb 18, 2021

@gaearon
Collaborator

Mostly because the downsides of double rendering console logs, in our experience, outweigh the downsides of missing logs from one of them. We plan to make this configurable via DevTools. In the meantime you can do let log = console.log in outer scope and it’ll work on both renders.

exposir

exposir commented on Oct 20, 2022

@exposir

Mostly because the downsides of double rendering console logs, in our experience, outweigh the downsides of missing logs from one of them. We plan to make this configurable via DevTools. In the meantime you can do let log = console.log in outer scope and it’ll work on both renders.

Learned

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @gaearon@ykforerlang@exposir@sschultze@ecnatsiDehTog

        Issue actions

          Concurrent mode renders components twice with different identities · Issue #17786 · facebook/react