Ability to handle components with multi-stage rendering #475
-
I think this library is really awesome and I love your examples in Storeybook. I've found an issue when working with components that render in multiple stages (eg some sub-components render faster than others) with dynamic heights. When you scroll down such a list and you get close to the bottom of the list there is a jumping effect where the scroll jumps back upward after some of the slower sub-components render. This actually prevents the user from scrolling to the bottom of the list in some cases because it happens every time you scroll down. I've got a minimal reproducible example here and recorded a video to show the issue. Does anyone have advice on how to prevent this kind of jumping behaviour at the bottom of the scroll? Edit: I understand that I could un-nest these components in the simple example, however, in practice the components are much more complicated, have more than one level of nesting, and will be very impractical to un-nest. scroll-jump.movHere is the code: import { useState, useEffect, forwardRef } from "react";
import { VList } from "virtua";
function App() {
return (
<>
<div style={{ height: "400px", border: "1px solid black" }}>
<VList style={{ height: "100%", width: "100%" }}>
{Array.from({ length: 100 }).map((_, index) => (
<TwoStageRenderItem key={index} index={index} />
))}
</VList>
</div>
</>
);
}
const getRandomHeight = () => Math.floor(Math.random() * 100) + 50; // Random height between 50 and 150 px
const getRandomDelay = () => Math.floor(Math.random() * 300) + 100; // Random delay between 100 and 400 ms
export const TwoStageRenderItem = forwardRef(({ index }, ref) => {
const [immediateHeight] = useState(() => getRandomHeight());
const [delayedHeight, setDelayedHeight] = useState(null);
useEffect(() => {
const delay = getRandomDelay();
const timer = setTimeout(() => {
setDelayedHeight(getRandomHeight());
}, delay);
return () => clearTimeout(timer);
}, []);
return (
<div ref={ref} style={{ border: "5px solid black", margin: "5px 0" }}>
<div style={{ height: immediateHeight, background: "#e0e0e0" }}>
Immediate Content {index} (Height: {immediateHeight}px)
</div>
{delayedHeight !== null ? (
<div style={{ height: delayedHeight, background: "#f0f0f0" }}>
Delayed Content {index} (Height: {delayedHeight}px)
</div>
) : (
<div style={{ padding: "10px", background: "#ffe0e0" }}>Loading...</div>
)}
</div>
);
});
TwoStageRenderItem.displayName = "TwoStageRenderItem";
export default App;
|
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 4 replies
-
I changed jump compensation logic of virtua at 0.29.0 to support more features. As a workaround, you can use earlier versions which may not have this jumping near bottom problem. I'm planning to fix this problem asap, probably in a few weeks. |
Beta Was this translation helpful? Give feedback.
@jackhodkinson
Could you try
0.33.4
? At least it's much improved.#476