petyosi / react-virtuoso

The most powerful virtual list component for React
https://virtuoso.dev
MIT License
5.25k stars 301 forks source link

Scrolling is staggered when rendering image tags #135

Closed Astra-RX closed 3 years ago

Astra-RX commented 4 years ago

Currently list items height are immediately determined and updated on resize. When rendering an image, the height is known after the image loaded, therefore the total height changes during scrolling and feels staggered.

How about introducing an onload callback for async rendering, or using the native onload perhaps?

jmeistrich commented 4 years ago

I'm not sure how or even whether react-virtuoso should solve this? I think this would be solvable inside the rendered component by rendering a 0 height div until the image is loaded. Then it would only render once with the loaded image.

But you would still have a rendering jump since the render would be coming in asynchronously after scroll. I had a similar problem in my app and my solution was to cache the known image sizes. Another approach could be to pre-load images in the background so that when the element comes into view the image is already cached.

Or am I missing an obvious solution I didn't think of?

Astra-RX commented 4 years ago

@jmeistrich yes, these methods came out first too when I was thinking about this. I also took a look at Slack, texts and images were fixed height placeholders when they are loading, which is probably not very useful. The use case may be specific, but I think to support async load with callback on item renderer is a useful feature.

Btw, could you give me more detail on how to preload images without re-rendering? 0-height div sounds promising.

jmeistrich commented 4 years ago

@Artoria-0x04 You can render an image with display: none and it will still load the image and fire the onLoad event. Then you can get the naturalWidth and naturalHeight (the original size of the image before the browser resizes it).

Or alternatively you can render the image inside a container with { height: 0, overflow: 'hidden' } and it well render normally but just not be visible. Then once it's loaded, remove that style and it will display normally.

I made a jsfiddle of both examples: http://jsfiddle.net/pgm13fen/1/

Astra-RX commented 4 years ago

Thanks, I'll give it a try

petyosi commented 4 years ago

A thing that might help in such case is the scroll seek mode behavior.

mayurkalia99 commented 2 weeks ago

A thing that might help in such case is the scroll seek mode behavior.

This is not available on VirtuosoMessageList.

petyosi commented 2 weeks ago

@mayurkalia99 I would not recommend having images with unknown size in the first place. There are several issues that describe the problem.

mayurkalia99 commented 2 weeks ago

<Image className="max-h-[120px] max-w-[400px]" blurDataURL={file.file_url} src={file.file_url} width={120} height={400} alt={file.name} onClick={() => file && handleFileClick({ filename: file.name, url: file.file_url, fileType: file.type, }) } /> Using next/image like this, passing specific width and height.