-
Notifications
You must be signed in to change notification settings - Fork 2
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
feat: Grid table virtualization #93
Conversation
@@ -245,7 +243,6 @@ export function GridTable<R extends Kinded, S = {}, X extends Only<GridTableXss, | |||
isCollapsed, | |||
toggleCollapsedId, | |||
...sortProps, | |||
persistCollapse, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This prop was being passed but not used
...((rowStyle?.rowLink || rowStyle?.onClick) && { | ||
// Even though backgroundColor is set on the cellCss (due to display: content), the hover target is the row. | ||
"&:hover > *": Css.cursorPointer.bgColor(maybeDarken(rowStyleCellCss?.backgroundColor, style.rowHoverColor)).$, | ||
}), | ||
...maybeApplyFunction(row, rowStyle?.rowCss), | ||
}; | ||
|
||
const TableRow = as === "div" ? "div" : "tr"; | ||
const Row = as === "table" ? "tr" : "div"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Most of the changes from here down are flipping logic from if div ... else table
to be if table ... else div
because the "else div" applies to both as div
as well as as virtual
.
a6ce36b
to
7088074
Compare
...Css | ||
// Apply the between-row styling with `div + div > *` so that we don't have to have conditional | ||
// `if !lastRow add border` CSS applied via JS that would mean the row can't be React.memo'd. | ||
// The `div + div` is also the "owl operator", i.e. don't apply to the 1st row. | ||
.addIn("& > div + div > *, & > tbody > tr ", style.betweenRowsCss) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This renderCssGrid
got simpler b/c the table logic got moved into renderTable
, which also made things like maybeWrapWith
go away, so I think turned out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🍣 I've checked out the Storybook and it's neat to see the virtualization. I was surprised that it did not keep the already rendered div's though as the work has been done (maybe for really really big tables it's worth removing them).
@@ -120,7 +124,7 @@ export interface GridTableProps<R extends Kinded, S, X> { | |||
* @example | |||
* { header: "Name", data: ({ name }) => name, w: "75px", align: "right" } | |||
*/ | |||
as?: TableAs; | |||
as?: RenderAs; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thoughts on defaulting to Virtual all the time? Is there any benefit not to? And Keeping as
the way it was?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that the as=virtual
needs its container to be pinned to "effectively 100% - chrome/padding/whatever", so I don't think we can just flip existing usages over.
Also I think virtual has a slightly worse UX for things like "find in page"...
But, dunno. I'd thought of something like "if number of rows is over 100, flip to virtual by default if as
isn't explicitly set to div or table", but I think that'd be even trickier to get right on "my DOM parent sometimes / sometimes doesn't need to set the height in this specific way".
I see that they mentioned they work with Grid (they are headless) but wondering if the API gives us anything to get rid of the |
Yeah, afaict basically none of the virtualization libraries do that, but they each have issues requesting it: I've also tried to google around about how to "keep DOM nodes that you don't technically want in the DOM" and it seems like React just doesn't like doing that. I.e. tricking the reconciler to keep around the DOM node that is already rendered is really hard to do, at least with a provided-by-React API/approach. So I think you'd have to resort to like "keeping it in the DOM but display: none" or something like that. Which ... would probably work? Dunno. I agree it seems like an obvious thing to try and do... 🤷 Maybe we can try and do a PR for react-virtuoso on next hack day. :-) |
I think we worked on a few tickets to get our tables to scroll to a certain sections, this would be nice to use https://virtuoso.dev/scroll-to-index/ |
This way we can get rid of the table approach! |
Yeah I saw that, but didn't think it was for "rows in a table", vs. just "a long list of items". Granted, that is what CSS grid is... And yeah, they do mention "css grid" there, which I'd missed... (good catch) That said, the reason we added the extra " |
Yep! Wanted to leave it out of this initial PR but saw that / agreed we should figure out how to use it. |
12ea5ce
to
3ae470f
Compare
## [1.35.0](v1.34.0...v1.35.0) (2021-06-03) ### Features * Grid table virtualization ([#93](#93)) ([3af84a5](3af84a5))
🎉 This PR is included in version 1.35.0 🎉 The release is available on: Your semantic-release bot 📦🚀 |
See comments but I played around with:
react-window
(looks like it was the best, but maintainer has moved on, and I couldn't immediately get it to play nicely withdisplay: contents
),react-virtual
(headless just-a-hook, looks really small and tight but right away was pretty finicky), and ended up onreact-virtuoso
(seems like the new "best" and is actively maintained, tons of features, but also largest bundle size I've heard but not actually checked/compared)Also, specifically
react-virtuoso
seems to be the only library that does measured per item sizing.react-window
let's you provide a size variable (like we would have a per-kindRowStyle[kind].height
) but AFAIU (could be wrong, but I think?) you have to know it up-front without measuring it from the DOM. Same with react-aria'suseVirtualization
afaict (I looked into the source code and eventually got to "these table rows are X height, those are Y height"). So, dunno, I think know-height-ahead-of-time-based-on-row-kind would be an okay limitation for us if we had to go that way, but the "meh just measure it and it magically works" is pretty great imo.I extended the
as
fromtable | div
totable | div | virtual
, which ended up being a pretty nice/cute slice point.I did have to patch react-virtuoso to work around "
display: contents
shows up as height zero":petyosi/react-virtuoso@master...homebound-team:probe-item-size
And am working on upstreaming it:
petyosi/react-virtuoso#375
UPDATE: ^ is now merged into the latest react-virtuoso link, and I've updated the PR to use that instead of our fork.