Skip to content

Bug: (17.0.0-rc.1) lazy is eager in dev mode #19748

Closed
@nstepien

Description

@nstepien

React version: 17.0.0-rc.1

Steps To Reproduce

  1. Create elements out of lazy components, use them conditionally.
  2. Check if the lazy components are dynamically imported.

Link to code example: --

main.jsx:

import React, { lazy, Suspense, useState } from 'react';
import { render } from 'react-dom';

const Checked = lazy(() => import('./Checked'));
const Checked2 = lazy(() => import('./Checked2'));
const Unchecked = lazy(() => import('./Unchecked'));
const Unchecked2 = lazy(() => import('./Unchecked2'));

function App() {
  const [checked, setChecked] = useState(false);

  const checkedElement = <Checked />;
  const uncheckedElement = <Unchecked />;

  return (
    <>
      <label>
        <input
          type="checkbox"
          checked={checked}
          onChange={e => setChecked(e.target.checked)}
        />
        Toggle me
      </label>

      <hr />

      <Suspense fallback="loading...">
        Checked? {checked ? checkedElement : uncheckedElement}
      </Suspense>

      <hr />

      <Suspense fallback="loading...">
        Checked? {checked ? <Checked2 /> : <Unchecked2 />}
      </Suspense>
    </>
  );
}

render(<App />, document.getElementById('app'));

Checked.jsx:

export default function() {
  return 'Checked';
}

Checked2.jsx:

export default function() {
  return 'Checked 2';
}

Unchecked.jsx:

export default function() {
  return 'Unchecked';
}

Unchecked2.jsx:

export default function() {
  return 'Unchecked 2';
}

The current behavior

The Checked.jsx chunk is imported eagerly, even though the component isn't immediately rendered.
image

This doesn't happen in prod mode, or with React 16, or with components that are not createElement-ed eagerly.

This affects react-router, as it uses this pattern:

<Router>
  <Suspense fallback={<Loading />}>
    <Switch>
      <Route exact path="/">
        <Home />
      </Route>
      <Route exact path="/demo">
        <Demo />
      </Route>
      <Route>
        <NotFound />
      </Route>
    </Switch>
  </Suspense>
</Router>

AFAICT it doesn't break anything, but it is unexpected/confusing.

The expected behavior

lazy components that are not rendered should not be dynamically imported.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions