-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Collections with dynamic heights #563
Comments
Hey @chrislloyd. Thanks for sharing these thoughts. 😄 One of the tricky things about what you're proposing is that- without knowing the width/height of a given cell,
Reflow is one perf consideration but not the only one. Every time |
First off, thanks for taking the time to reply — this is very exciting!
Yep — I'm not really interested in trying to follow those either. It'll just end up too messy.
We currently batch the pre-rendering of the cells to split that cost across multiple frames. It does create some scroll jerk but it tends to not be a problem as it's in line with what users are seeing visually. Though I haven't played around with Fiber too much, I'm hoping that will help with this problem eventually.
I think it's a tradeoff. We're currently employing a technique similar to this (albeit not using React) and real world perf is OK. We'd obviously love to utilize RV, so a few possible approaches come to mind:
Cheers! |
We might be misunderstanding each other. I think it's important that such a component as we're discussing not have to measure every cell in it before laying out the first chunk of cells. Sounds like your use-case is < 1k items but we shouldn't expect that to be the case for other users. RV components are regularly used with 10s or 100s of thousands of items. 😁 Fortunately I don't think it would be that complicated to implement either. |
Here's a rough sketch of what I had in mind: const { maxCellHeight, maxCellWidth } = this.props
const { scrollLeft, scrollTop } = this.state
const viewportRight = scrollLeft + width
const viewportBottom = scrollTop + height
// Items that may be visible in the currently scrolled viewport.
// Perhaps we could short-circuit this filter by tracking filtered coordinates.
const filteredItems = items.filter((item) => {
const id = item.id // Over-simplification :)
let position;
if (cachedPositions.hasOwnProperty(id)) {
position = cachedPositions[id]
} else {
cachedPositions[id] = position = cellPositionGetter({ index })
}
if (
isVisible({
left: position.left,
top: position.top
})
) {
return true
}
const maybeVisible = isVisible({
bottom: position.top + maxCellHeight,
left: position.left,
right: position.left + maxCellWidth,
top: position.top
})
// Depending on how big maxCellHeight/maxCellWidth are,
// We may not even need to ACTUALLY measure the items.
// It might be okay to just render them anyway.
// But if we need to, we can further filter.
if (maybeVisible) {
const measurement = cachedMeasurements.hasOwnProperty(id)
? cachedMeasurements[id]
: measure(item) // CellMeasurer hook
return isVisible({
bottom: position.top + measurement.height,
left: position.left,
right: position.left + measurement.width,
top: position.top
})
}
return false
}) Something like this ^ should allow us to defer actually rendering and measuring cells until they are likely to actually be displayed. |
Hey @chrislloyd! Unfortunately I'm not going to make it to React Wed tomorrow. Something came up that I need to take care in the afternoon near home. But I'd love to talk more about this at some point. Perhaps we could do a Hangout or Messenger video chat. 😄 |
This issue isn't really actionable without some further discussion- which we have planned for the next React Wednesday and/or during React Conf- so I'm going to close this issue for now as I don't like to leave non-actionable issues hanging around. Let's talk more about this in person! We can open issue(s) as needed once we decide on a plan. |
As mentioned in person to @bvaughn, I'd like to start using React Virtualized for laying out collections of items with dynamic heights. While
Collection
is super useful, the user needs to know the width and height of a cell before rendering it, which is difficult when cells contain text. What does this mean practically? Well I'd love to see/build something like this:Basically, instead of the
width
andheight
having to be calculated by the caller, theCollection
can render the item, measure it's width and height, then pass that tocellSizeAndPositionGetter
. From there, thecellRenderer
just needs to be away of wether the cell is in view or not and can toggledisplay: none
appropriately. React Virtualized would need to render all the items (preferably in batches) and leave them in the dom. However, if they aredisplay: none
'd when not visible, they won't affect reflow perf.Another thing to consider is that server rendering these Collections is impossible. In that situation it might be worthwhile providing an extra property to the
cellRenderer
likeisMeasuring
so that clients could specify a server fallback. As an example taking the layout from the RV Collection docs, clients could float position cells so that the first line is correctly positioned server side.One alternative interface would be to add
display: none
to thestyles
prop passed to thecellRenderer
so that users wouldn't need to worry about it themselves, however that gives less flexibility in how the styles are applied (it would be more efficient to use CSS selectors rather than inline).This is all a bit of a brain dump about the topic, but I'd like to gage the interest for something like this in Virtualized and see wether the approach is 🆗 before committing to a PR :)
The text was updated successfully, but these errors were encountered: