[Masonry][lab] Fix layout flicker issue and ResizeObserver loop error - #38427
DiegoAndai wants to merge 11 commits into
Conversation
Netlify deploy previewhttps://deploy-preview-38427--material-ui.netlify.app/ Bundle size reportDetails of bundle changes (Toolpad) |
ef77710 to
91a13d2
Compare
91a13d2 to
7289646
Compare
|
do not use map children and clone element. The underneath element may not accept style prop. |
|
I basically have resolved the flicker issues in my own infinite photo gallery masonry component. I can provide some more important steps below, but the resize observer loop issue sometimes happened but rarely.
If you need the code, I will write a minimal demo out of our project in my bare time. |
|
Off-topic: I think Masonry should start using |
|
Thanks for the feedback both! @tangye1234 regarding some of your points:
I don't understand this point. Some code might help to understand better 😅
This is not possible as we use
Do you have a repro case for this? @siriwatknp I refactored with your suggestion, so it's ready for re-review 😊
Yeah, I think whenever we wish to refactor the Masonry, we should use |
Hi, here is my demo: https://stackblitz.com/edit/stackblitz-starters-ktbdbe?file=components%2Fmasonry.tsx I use the styled-components to make the masonry component. |
siriwatknp
left a comment
There was a problem hiding this comment.
👍 Looks good to me. @mnajdova Do you have some context about the Masonry? would be great to have another eye on this.
|
Thanks for sharing your code @tangye1234! I replied to you in #36673 (comment) |
mnajdova
left a comment
There was a problem hiding this comment.
Fix layout flicker issue
I would rephrase this to "Improved layout flicker", so that we don't give wrong expectations - there is still flickering when changing the opacity value.
Hide the initial rendering using opacity: 0 before the initial calculation is done. Before this initial calculation, the component is not ready to be shown, so hiding it makes sense.
This is the only thing I am not 100% certain about, but I don't have a better proposal. The main reason is that, usually the Masonry component will wrap almost the whole page - imagine dashboard, image gallery etc. This will mean that the response from the server will always be fully hidden.
|
@mnajdova I reverted the opacity, default height, and We should only merge this once we find a better solution for the flickering on the initial rendering. It is still not acceptable. I had the following idea: Add a new effect (see commit). This effect should run But, for some reason, I still get the initial flickering (see attached video). The I'm stuck here. Would you happen to know why this is not working? I would appreciate it if you could take a look 😊. Masonry-flicker.mov |
We already have a |
The idea for the new The existing one sets up the observer for subsequent resizes. On that one, we need That's the theory. It's not working though 😅 |
|
Hi there, any news about this?? Just 1 test is pending! :) |
|
Hey @luisjavierbautista, thanks for the interest! I haven't found a better solution for my comment here. I think it might be better to remove the |
|
Converting this to a draft as it's not ready yet. The thing missing is to solve the initial render flicker. All my thoughts are in the PR's description and comments. I cannot allocate more time to keep working on this right now. I can provide guidance if anyone wishes to continue it or propose another solution. |
Closes: #36673
Context
The Masonry component initially renders all the items (in one row) to measure their computed heights. Then, it places them in the corresponding columns, which results in a flicker between the initial render and the ordered render.
This flicker was made worse by #37208, which fixed #36909. The issue was that a
ResizeObserver looperror would show up, and the fix was to handle the loops by usingrequestAnimationFrame. The usage ofrequestAnimationFramedelays the placement, making the flicker more noticeable.Here's a good explanation for the
ResizeObserver looperror: https://webkit.org/blog/9997/resizeobserver-in-webkit/#:~:text=observation.-,How%20Observations%20are%20Delivered.Changes
ResizeObserver looperror would occur, which we can fix:8pxspacing and two items of100pxheight each. The max height of the Masonry in that state is116px, as we added spacing as margin on top and bottom of each item. When adding a200pxitem, it would shrunk to116px, the previous max-height, but because we added spacing on top and bottom to the new item, its actual height was132px. The new item triggers the observer, and the max height would be set to132px, and the item's new height to148px. It would loop until the actual item's height was 200px. The loop is avoided by not allowing the items to shrink withflex-shrink: 0. A video of this example is added below. You'll think that this would cause the added item never to reach its height ifspacingis0, and indeed that's the case: https://codesandbox.io/s/masonry-shrinking-loop-k5hhqrrequestFrameAnimationfor the observing setup fixes this issue. The difference from #37208 is that the delay is on the observing setup, which is invisible to the user, instead of the placement calculation.Video of the shrinking loop
Adding a debugger call between renders allows us to appreciate the shrinking loop. The partially calculated column heights appear at the bottom of the recording.
Screen.Recording.2023-08-21.at.12.52.08.mov