Skip to content

Bug: State updates in ResizeObserver callbacks are applied after paint and cause visual glitches #24331

@guillaumebrunerie

Description

@guillaumebrunerie

React version: 18

When a state value gets updated in a ResizeObserver callback, I believe that React should make sure that the DOM is up-to-date before the next paint. Otherwise, if we are using ResizeObserver to do some visual changes to some part(s) of the app as soon as some element resizes (which seems like a reasonable assumption), it can create visual glitches.

It worked fine in React 17, but in React 18 the state updates seem to be deferred to a later time (unless flushSync is used). This is most likely due to the "batch state updates" change in React 18.

Steps To Reproduce

In the example below we use a ResizeObserver to make sure that the width of the blue div always matches exactly the width of the grey textarea under it.

  1. Quickly resize the grey textarea. Notice that the width of the blue div lags behind.
  2. Turn on the shouldUseFlushSync flag in the code and quickly resize the grey textarea again. Notice that they now stay perfectly in sync, the glitch is gone.

Link to code example: https://codesandbox.io/s/amazing-montalcini-j6lz46?file=/src/App.js (tested in Chrome on Linux)
(it is probably more visible on a slow computer, you can try enabling CPU throttling if you cannot see it)

The current behavior

We need to use flushSync in order for the app to work without glitches.

The expected behavior

Given that it is probably pretty common to use ResizeObserver to make sure that some part of the app stays visually in sync with some other part of the app, I would expect React to guarantee that updates triggered in a ResizeObserver callback will be applied before the browser gets the chance to paint the resized element, and without expecting the developer to use the somewhat obscure flushSync method.

Related

I could only find one related issue: #21119, but it is about batching several updates coming from the same callback. It's perfectly fine to batch several updates coming from the same ResizeObserver callback (or even from several such) as long as they are guaranteed to be applied before the resized element is painted again by the browser.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Resolution: StaleAutomatically closed due to inactivityStatus: UnconfirmedA potential issue that we haven't yet confirmed as a bug

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions