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

Autosizer sets state in componentDidMount causing a nested update #88

Closed
dinkinflickaa opened this issue Mar 24, 2024 · 3 comments
Closed

Comments

@dinkinflickaa
Copy link

dinkinflickaa commented Mar 24, 2024

Autosizer sets state in componentDidMount phase which will block browser from repainting. This can be a big performance bottleneck.

Here is a codesandbox to demonstrate how changing state in componentDidMount phase can take longer to paint

https://codesandbox.io/p/sandbox/react-class-forked-5ffvgl?file=%2Fsrc%2Findex.js

Trace with state change inside componentDidMount
image

Trace without state change inside componentDidMount
image

Has anyone else run into this? Can we get the state changes before the first rather and avoid a nested update?

@dinkinflickaa dinkinflickaa changed the title Autoresizer changes state during mount phase causing a nested update Autosizer sets state in componentDidMount causing a nested update Mar 24, 2024
@bvaughn
Copy link
Owner

bvaughn commented Mar 24, 2024

Layout effects are permitted when a component should re-size its contents before the browser paints. (This is done to avoid flickering/shifting.)

The main problem in the above screenshot is either (a) something in your code is triggering repeated renders+updates or (b) one or more of your components is doing too much work in render to be able to update quickly. Hard to tell which.

@bvaughn bvaughn closed this as completed Mar 24, 2024
@dinkinflickaa
Copy link
Author

Layout effects are permitted when a component should re-size its contents before the browser paints.

@bvaughn
In this case aren't we triggering resize manually though? See: https://github.com/bvaughn/react-virtualized-auto-sizer/blob/master/src/AutoSizer.ts#L65C1-L66C1

The main problem in the above screenshot is either (a) something in your code is triggering repeated renders+updates or (b) one or more of your components is doing too much work in render to be able to update quickly

The screenshot is taken from codesanbox link's browser trace. https://codesandbox.io/p/sandbox/react-class-forked-5ffvgl?file=%2Fsrc%2Findex.js

All it does is:

  1. On Page load renders 10k components. Nothing virtualized.
  2. Each component implements a useEffect mount and cleanup.
  3. On click, Re-creates the class component which changes a text property in componentDidMount

So there aren't repeated re-renders but paint is delayed here because it has a lot of slow side effects which have to be flushed synchronously because of the nested update. This can be quite terrible when you are unmounting a lot of components before mounting AutoSizer

@bvaughn
Copy link
Owner

bvaughn commented Mar 24, 2024

I'm not sure what to say, except...don't re-render 10k components like that 😄 It's never going to be performant. Switching from a layout effect to a passive effect will not make a difference in many cases, (often something else will trigger a sync update which will cause React to also flush passive effects before proceeding). And even if that's not the case, it's still going to take a ton of CPU time.

Layout effects are for layout (resizing and positioning) which is exactly what this component does.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants