Closed bvaughn closed 1 month ago
@afreix @tastyqbit I am fairly certain your issues on Safari and Internet Explorer are due to the lack of support for ResizeObserver in those browsers. I had exactly your issue (scrolling back fixed it) and adding a polyfill solved it for me. See MDN for compatibility tables.
I think the lack of ResizeObserver should generate a warning in the console.
What about something like this https://codesandbox.io/s/agitated-jennings-o9nn6 ?
basic using VariableSizeList + ItemMeasurer from #102 I know this is very naive approach but looks like it's kinda working ( not that bad 😂) as temporary solution 🤔
In our team we came across the need to render a large list of random sized textual data. For us the ability to accurately jump between items and scroll without any lags was a must. After quite a bit of online searching I gave up and wrote this library. Hope it helps as a temporary solution for some of you :smile_cat:
Hey, Just wanted to update that after some work I think that the library came to a decent state and could be a good solution if your items don't change their size after being rendered for the first time.
@gnir-work what if the window resizes and the container size changes causing the list to resize?
Reading this thread and I think there might be a better way to handle items that have a width that can change.
The definition of 'variable' here is variable over the whole set. The actual items size is static, not dynamic. Maybe dynamic is a better term because the size can change during resize or mutation if the text changes.
The way this could work is to listen to the the scrolling on the parent.
The algorithm would work like this:
compute an estimated size for each item - this needs to be very efficient. It doesn't have to be perfect. +- 20% is fine.
we only render items that are visible + say 20% more so that if the user scrolls they don't see any changes
We have a 'ghost' for everything else which has 'height' set to the estimated height. It's just an empty div. This way the scroll bar looks about right.
An item is only shown when it is in the viewport. Other than that the ghost items is shown.
The only downside to this is that the scrollbar height will change slightly. I'm not sure if this would be distracting to the user. Might be if the scroll list is large. We MIGHT be able to trick this by increasing/decreasing a buffer such that the estimated sizes don't impact the scroll bar length.
@gnir-work what if the window resizes and the container size changes causing the list to resize?
As of the latest version (2.2.0
) the component supports changes to the size of the the whole list (height and width).
Reading this thread and I think there might be a better way to handle items that have a width that can change.
The definition of 'variable' here is variable over the whole set. The actual items size is static, not dynamic. Maybe dynamic is a better term because the size can change during resize or mutation if the text changes.
The way this could work is to listen to the the scrolling on the parent.
The algorithm would work like this:
- compute an estimated size for each item - this needs to be very efficient. It doesn't have to be perfect. +- 20% is fine.
- we only render items that are visible + say 20% more so that if the user scrolls they don't see any changes
- We have a 'ghost' for everything else which has 'height' set to the estimated height. It's just an empty div. This way the scroll bar looks about right.
- An item is only shown when it is in the viewport. Other than that the ghost items is shown.
The only downside to this is that the scrollbar height will change slightly. I'm not sure if this would be distracting to the user. Might be if the scroll list is large. We MIGHT be able to trick this by increasing/decreasing a buffer such that the estimated sizes don't impact the scroll bar length.
This was already implement by @bvaughn in react-virtualized
. The main downside of this approach is that jumping to a specific row doesn't work well and creates visuals bugs when scrolling up.
@gnir-work ah.. ok... maybe I'll abort my work and look at react-virtualized.
I think you're right with the scroll up issues but I think I can fix this by having an 'estimated size', and then convert it to an actual size once the component mounts.
... but another issue of course is handling dynamic content. If something updates the component height changes.
If the estimated size is accurate than it may work, For example I implement sometime ago a virtualized list with dynamic height with react-virtualized and it worked well as long as the estimated size was exact. Otherwise the scroll to row functionality would break my app ☹
Sent from Mail for Windows 10
From: Kevin Burton Sent: Tuesday, 14 April 2020 23:07 To: bvaughn/react-window Cc: Nir Geller; Mention Subject: Re: [bvaughn/react-window] Support just-in-time measured content (#6)
@gnir-work ah.. ok... maybe I'll abort my work and look at react-virtualized. I think you're right with the scroll up issues but I think I can fix this by having an 'estimated size', and then convert it to an actual size once the component mounts. ... but another issue of course is handling dynamic content. If something updates the component height changes. — You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or unsubscribe.
-- This email has been checked for viruses by Avast antivirus software. https://www.avast.com/antivirus
@gnir-work ah... I don't need the 'scroll to row' functionality I think.. though maybe I'm wrong.
That this should suffice for your needs 😊
Sent from Mail for Windows 10
From: Kevin Burton Sent: Tuesday, 14 April 2020 23:13 To: bvaughn/react-window Cc: Nir Geller; Mention Subject: Re: [bvaughn/react-window] Support just-in-time measured content (#6)
@gnir-work ah... I don't need the 'scroll to row' functionality I think.. though maybe I'm wrong. — You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or unsubscribe.
-- This email has been checked for viruses by Avast antivirus software. https://www.avast.com/antivirus
As a workaround if:
you can use CanvasRenderingContext2D.measureText() tо calculate row height instead of rendering whole component :poop:
@bvaughn Any plans on publishing a new alpha version on npm? We haven't had any update since 1.6.0-alpha.1
😕
@bvaughn any updates? will it be fixed in recent versions?
For those wanting to use Typescript with DynamicSizeList
- module augmentation can give the types needed for DynamicSizeList
working off of the DefinitelyTyped definitions (a workaround to my query posted in this thread last year).
Add the follow to the project:
import React, { Component } from 'react'
declare module 'react-window' {
export type DynamicSizeListProps = Omit<FixedSizeListProps, 'itemSize' | 'scrollToItem'>
export class DynamicSizeList extends Component<DynamicSizeListProps> {}
}
Then import as usual:
import {
DynamicSizeList,
DynamicSizeListProps,
} from 'react-window'
// use as normal...
@types/react-window
still needs to be installed first for the FixedSizeListProps
definition.
Thanks for the typedefs, going to add them now! I've been using DynamicSizeList in prod for over a year now. Currently based on this fork: "@john-osullivan/react-window-dynamic-fork": "^1.9.0-alpha.1"
(is that the most up to date thing still?). I tried to switch to react-virtuoso
because of the uncertainty about if/when this would actually be released. But found it less performant and stuck w/ this.
@bvaughn is it time yet to pave the cowpath and release this to npm? Maybe just renamed to ExperimentalDynamicSizeList
if you're still worried about it not being ready.
Hello guys! Thank you for your hard work and this great library. I'm really looking forward for this feature! However, I would suggest to add information regarding this issue to the README and documentation/examples. It took me quite some time to figure out that dynamic content is not actually supported by the library and it's only useful for items with fixed/known size. I believe the README has a nice FAQ section where this could be added.
if you are looking for a table/grid/tree, this would be a good start https://autodesk.github.io/react-base-table/examples/dynamic-row-heights, built on VariableSizeGrid
@tony-scio can you please share a working codesandbox for using DynamicSizeList from 1.6.0-alpha.1 with InfiniteLoader? Thanks, I would really appreciate it.
Has anyone gotten this to work with react-beautiful-dnd? Dragging seems to make the items jump on top of each-other.
Has anyone gotten this to work with react-beautiful-dnd? Dragging seems to make the items jump on top of each-other.
i will also wait for this answer :D
[HELP] There is no code for show at this link: dynamic-size-list-vertical and I need this ability. THANKS
[HELP] There is no code for show at this link: dynamic-size-list-vertical and I need this ability. THANKS
https://react-window-next.now.sh/#/examples/list/dynamic-size
Any update on this? We need something similar as we can (it's usually very few, but in some cases can be a lot) render a large responsive grid list of items (their heights are dynamic and will change on mobile as various text wraps etc). I feel react-window
would be a game changer if it could handle this use case. If not, are there any reliable alternatives?
Any update on this? We need something similar as we can (it's usually very few, but in some cases can be a lot) render a large responsive grid list of items (their heights are dynamic and will change on mobile as various text wraps etc). I feel
react-window
would be a game changer if it could handle this use case. If not, are there any reliable alternatives?
@JavaJamie since you specifically asked for alternatives - the react-virtuoso library comes with built-in support for measuring dynamic content. Disclaimer: I am the author of it.
@JavaJamie since you specifically asked for alternatives - the react-virtuoso library comes with built-in support for measuring dynamic content. Disclaimer: I am the author of it.
react-virtuoso is also double the size of react-window. Always have to keep dependency size in mind.
https://bundlephobia.com/result?p=react-window@1.8.6 https://bundlephobia.com/result?p=react-virtuoso@0.20.1
I have accepted the fact that I don't have the time or energy to finish this effort. If anyone would like to step in and finish the branch I started, I'd welcome your help. (Please also see issue #302 for how this would fit into version two release as the new List
and Grid
components.)
We ended up implementing something from scratch for this such that used visibility sensors which worked out really well.
I could probably OSS it or point you guys to the right place if you want to rip it out and create a new project or move it here.
One trick is we used 'blocks' so that we could increase performance. Basically we take each row, and actually put it into a parent block of like 25 items, then swap that in when necessary.
@burtonator it would be really helpful
Can anyone provide a bug-free implementation of react-select with DynamicSizeList? I can't get it to work well together. Currently I face 2 problems (sorry for no screenshots):
style={position: absolute, left: 0, top: 0}
which doesn't let me use this style since all options sit on top of each other.Could not find any working example of the two. I'll note that I use the 1.9.0 fork, on Chrome.
Edit. Found an answer here above, in the hidden comments section. https://github.com/bvaughn/react-window/issues/6#issuecomment-509016422
One simplification to the scrolling issue would be to use the scrollbar to indicate the index of the item in the list instead of a pixel position, if the scroll is more than roughly one viewport height away. Instead of attempting to "scroll down" X pixels, the component simply renders the items around the desired index. Halfway down renders item at index N/2, and at bottom renders item at index N-1.
That would allow direct thumb scrolling to the middle or end of the list, without the lagging of the scroll thumb while the component renders and calculates sizes. Right now, for very long VariableSizeList components, it's nearly impossible to scroll to the bottom as the cursor drags faster than the scroll thumb moves.
Is here something in progress or this feature is freezed?
I want to use this feature because Lighthouse keeps complain about Excessive DOM. However, it has been so many years now. Is there any alternation towards this? Another project? Since the author doesn't have much time and effort to continue this?
react-virtual
might solve this problem for some people here. It supports dynamic measurement rendering.
react-virtuoso is another option that has this feature.
Would you take a look at this sandbox, I tried to create a DynamicSizeList based on VariableSizeList https://codesandbox.io/s/dynamic-size-list-zcntp
Any progress on this one?
Any update?
Hello. https://github.com/inokawa/virtua might help you if you want to virtualize dynamic content out-of-the-box.
In order to avoid adding cost to existing list and grid components, create a new variant (e.g.
DynamicSizeList
andDynamicSizeGrid
). This variant should automatically measure its content during the commit phase.MVP
The initial implementation of this could work similarly to how
CellMeasurer
works in react-virtualized:Goal
This component could perform better if we removed the third constraint above, allowing random access (by either item index or scroll offset) without measuring the preceding items. This would make react-window much more performant for use cases like chat applications.
This would also unlock the ability to use a ResizeObserver (via react-measure) to automatically detect item sizing and remove the position and measurements cache entirely. This would remove the need for imperatively resetting cached measurements and dramatically improve the API.
In order for the above to be possible, the dynamic list/grid components would need to use a dramatically different approach for mapping offset to index and vice versa. (This comment about "scroll anchoring" in react-virtualized has some nice visuals.) Essentially, we would need to do something like this:
Estimate total size based on the number of items multiplied by a
estimatedItemSize
prop. (This estimated size won't need to be adjusted, since the mapping described below doesn't is fuzzy.)When scroll position changes, compare the new offset to the previous offset. If the delta is greater than some [to be determined] threshold, set the new offset as the "scroll anchor". Map the offset to an estimated index (e.g. divide the offset by total estimated scrollable size and multiply that by the number of items in the collection). Store this mapped index as the "anchor index". For example, if the list described by the image below had 250 items, the "anchor index" would be 132.
The above approach has only one major downside: aligning items correctly at list boundaries. If item indices are estimated (as described above) then they likely won't line up exactly with the beginning or end of the scrollable area.
The end could potentially be accounted for by adjusting the total estimated size as the user scrolls closer to the end (although this might make scrolling feel janky).
The start of the list is harder to handle, since the first item needs to align with offset zero while still appearing to connect contiguously with items from some offset greater than zero. Perhaps another threshold could be used, a "safe zone", near the start of the list (e.g. if the scroll offset is less than some absolute value) which would force the list to measure all cells up to that point so they align correctly. The cost of this forced measurement would be relatively low, since it would only be a small number of items.
The one case that would still not be handled correctly with the above approach would be a scroll anchor that is set outside of the "safe zone" but a current scroll that goes inside of the safe zone (as shown below). If the user scrolls slowly back toward the beginning of the list, it may be difficult to align the first cell with zero without introducing scroll janky.