Skip to content

Bug: Hundreds render of Suspense child with hydration error #29922

@SuperOleg39

Description

@SuperOleg39

React version: 18.2

Description

Hello!

Found a few problem cases with Suspense, one quite exotic, one easy to reproduce, and in our project I get both at the same time.

First case - hundreds render of Suspense child with hydration error.

If wrapped in Suspese component cause hydration error, React will render this component hungreds or event thousands times.

Example:

function MissmatchCmp() {
  return <p>Missmatch Component {typeof window === 'undefined' ? 1 : 2}</p>
}

function App() {
  return (
    <>
      <Suspense>
        <MissmatchCmp />
      </Suspense>
    </>
  )
}
Снимок экрана 2024-06-18 в 12 13 41

Second case - Looped render of class component with setState in constructor wrapped in Suspense

Of course, setState in counstructor sounds like a bad pattern, but we have it in some big legacy class component.

Example:

class CmpWithSetState extends React.Component {
  constructor(props) {
    super(props);

    // emulate state change after http call
    setTimeout(() => {
      this.setState({ foo: "bar" });
    // with increased timout loop can be prevented
    }, 25);
  }

  render() {
    return <p>CmpWithSetState</p>
  }
}

function App() {
  return (
    <>
      <Suspense>
        <CmpWithSetState />
      </Suspense>
    </>
  )
}
Снимок экрана 2024-06-18 в 12 22 21

Bingo case - Both of previous examples in same component are guaranteed to cause a loop

Снимок экрана 2024-06-18 в 12 28 16

profiling-data.18.06.2024.12-28-19.json.zip

Steps To Reproduce

  1. Clone repo https://github.com/SuperOleg39/react-ssr-perf-test
  2. Switch to branch react-bug-suspense-child
  3. Run application build and server - cd react-18-stream && yarn && yarn start (use Node.js 16)
  4. Open application page at http://localhost:4000

Link to code example:

SuperOleg39/react-ssr-perf-test#1

The current behavior

Components which are not really suspended, rendered multiple times, like React wait for promise to resolve.

Also looks like React treats this components both as one when check if they are suspended or not.

The expected behavior

Expect the same behaviour as without Suspense boundary.

We use Suspense for our components mostly to prevent server rendering failure if one of this components failed.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions