bvaughn / react-window

React components for efficiently rendering large lists and tabular data
https://react-window.now.sh/
MIT License
15.9k stars 787 forks source link

[Feature request] Disable / control unmounting of already mounted rows #234

Closed olee closed 2 months ago

olee commented 5 years ago

I would like to suggest an option to control the unmounting of already mounted rows. This could give a performance boost to lists with a moderate amount of large rows but which are very expensive to render. If properly handled (rows should use memo of course) it would only render rows the first time they are visible and then keep them mounted to be able to scroll back to them again without needing to render them again.

What do you think of this suggestion? Might there be a way to do this with current react-window (or maybe react-virtualized?) right now?

bvaughn commented 5 years ago

I don't think that sounds like something I want to support directly. It sounds like a reasonable use case, I just don't think I want to take on the extra complexity.

You could perhaps implement this behavior by supplying your own innerElementType that's stateful and maintains a list of rows it's created by inspecting its props: https://github.com/bvaughn/react-window/blob/f2b2106cc828e9828cf2940411e5eab67f1d7aa6/src/createListComponent.js#L324-L331

But this would require some hacky duplication of this code: https://github.com/bvaughn/react-window/blob/f2b2106cc828e9828cf2940411e5eab67f1d7aa6/src/createListComponent.js#L285-L298

Bnaya commented 5 years ago

Out of curiosity: What's the painful part in your use-case? the DOM creation or react rendering? I think another approach is implementing DOM reuse, but it will require adding intermediate level of virtual keys.

olee commented 5 years ago

Keeping react components mounted is pretty much the same as DOM reuse. The initial rendering of new react nodes (ie. nodes that were added or have a new key) is the most expensive part of react rendering - subsequent updates are way faster. This is why I would love to see a library supporting virtual scrolling, but at the same time keeping already rendered components mounted (because as long as they don't exceed a quite large amount, this should be faster).

PS: Oh yeah another option for "DOM reuse" might be a way to make the virtual scrolling reuse the item keys. This should result in just their content being updated without making react disposing the old DOM elements and creating new ones. However for this to work the items would have to be implemented in a way that ensures they do not totally rely on componentDidMount for some rendering logic.

PPS: Actually I think this idea might be worth a try to see what performance benefits can me achieved with such a solution - I guess it could be tried out by adding a third parameter containing this kinda "window-static-key" here: https://github.com/bvaughn/react-window/blob/master/src/createListComponent.js#L305 So react-window would have to create a list of keys and once an item is rendered it get's assigned a key and will keep it, until it leaves the rendered range. Then the newly visible items would get that key assigned.

Bnaya commented 5 years ago

@olee I'm exploring possibilities when exposing the up-to-date overscan information to the keyProvider and cell components (its a patch on react-window), https://codesandbox.io/s/github/Bnaya/sticky-eurovision/tree/iteration Take a look at src/implementations/WithReactWindowDOMReuse/WithReactWindowDOMReuse.tsx

Using custom keyProvider and modulo i'm able to (almost) keep using same keys, and rotating them.

I think the idea behind it works, but right now react-window changing the overscan values in an unexpected way (for me) after the scroll ends. (losing one row and gaining it again right before next scroll) I will keep exploring that direction

Bnaya commented 5 years ago

I've made another iteration, when i'm using component state to track recycling, looks very promising In the picture we can see row 17 takes the components instances of row 2 Screen Shot 2019-06-06 at 17 13 02

There is still an issue when you scroll up to the ends and the rendered rows number is changing.

ghost commented 3 years ago

I have the same problem here... It would be great if there was a way which already-rendered items that fall out of the view, still be there and not unmount.

bvaughn commented 3 years ago

It would be great if there was a way which already-rendered items that fall out of the view, still be there and not unmount.

Since this is something React intends to provide support for natively with a future Offscreen API, I don't think a library like react-window should try to implement this itself.

codeaid commented 3 years ago

This is actually something that is causing some pain in the project I'm working on. I have a table where you can select and deselect rows and obviously they change background color. For a long time I couldn't understand why none of my CSS transitions were working until I realised that react-window is completely unmounting all my rows even though the only thing that changes is only the selected property on one of them.

Is there any reason why everything has to be destroyed when things that are not even relevant to virtualization change?

joseteIIo commented 2 years ago

Agree with @codeaid . It's also a big pain point for a project I am a part of.

erikiva commented 2 years ago

Having the exact same problem as @codeaid with a List, is there any way around this?

CarlosVergikosk commented 1 year ago

Same here, big pain. @codeaid

JustynaKK commented 4 months ago

hi, did anybody found nice workaround? I have very expensive initial rendering and I am looking for the way to avoid unmounting

CarlosVergikosk commented 4 months ago

hi, did anybody found nice workaround? I have very expensive initial rendering and I am looking for the way to avoid unmounting @JustynaKK use virtuoso.

JustynaKK commented 4 months ago

@CarlosVergikosk hi, I was checking virtuoso, but there is the same thing, everythig is unmounted on scroll