This is an umbrella issue to share my plans for the upcoming version 2.0 release of react-window
.
Feedback is appreciated and will be taken into consideration. I ask that you be understanding if I'm not able to accommodate all requests. I'll try to do my best to weigh feature requests against bundle size, runtime performance, and maintenance concerns.
I expect that upgrading from version 1 to 2 may require substantial code changes, many of which will not be possible to automate with code mods. Because of this, particularly for application code, I would advise against upgrading existing code unless you have a strong reason (e.g. you need support for dynamic size content).
I am also going to go ahead and pin the current docs to the domain react-window-v1.now.sh so they will not be lost when I update for version 2.
onScroll
callback timingOne way to help manage complexity is to reduce the number of components the library supports. I am currently planning on supporting only the following component types in version 2:
SimpleList
(previously FixedSizeList
)List
(previously DynamicSizeList
)ResizeObserver
API (or polyfill).Grid
(previously VariableSizeGrid
)One of the major changes from react-virtualized
to react-window
was the decision to treat children
as React elements (e.g. React.createElement(children, props))
) rather than as render props (e.g. children(props)
).
There were a couple of motivations for doing this:
React.memo
, useMemo
, shouldComponentUpdate
) so I didn't need to implement my own caching abstraction for item renderers.react-window
without requiring the render prop to pass them along (and without requiring cloneElement
calls).Unfortunately there were also some downsides:
itemData
and a custom areEqual
comparison export.After taking the above pros and cons into consideration, I've decided to convert to a render props approach for react-window
as well. This means that complicated examples like this can be re-written more easily:
const Example = ({ height, items, toggleItemActive, width }) => (
<List
height={height}
itemCount={items.length}
itemRenderer={({ index, key, style }) => {
const item = items[index];
return (
<div key={key} onClick={() => toggleItemActive(index)} style={style}>
{item.label} is {item.isActive ? "active" : "inactive"}
</div>
);
}}
itemSize={35}
width={width}
/>
);
Previously, list components supported both horizontal and vertical layout modes. In order to simplify implementation and maintenance, and because the overwhelmingly common use case is vertical lists, I will be removing support for layout="horizontal"
.
Grid components will continue to support direction="RTL"
, but lists will not (since they will only support a vertical layout). This tradeoff is being made to enable lists to be smaller and easier to maintain.
onItemsRendered
and onScroll
callback changesList and grid components currently support onItemsRendered
and onScroll
callback props. These callbacks are called during the commit phase (after the list or grid has completed rendering). This can be useful in that it is always safe to perform a side effect (like analytics logging) in response to these callbacks, but it has a downside as well: any scroll synchronized updates must be done in a second ("cascading") render.
Version 2 will make a change to the onScroll
callback to address this. The onScroll
callback will be called during the event's dispatch cycle so that any update will be batched (by React) with the list or grid's own update.
The onItemsRendered
callback will be replaced with a onItemsDisplayed
prop, although it will continue to be called during the commit cycle. This change is being made to enable the list component to more aggressively optimize render performance by pre-rendering at idle priority and make use of experimental APIs like display locking.
There are several pending deprecations (with DEV warnings) which will be removed:
innerTagName
and outerTagName
for all list and grid components. (Use innerElementType
and outerElementType
instead.)overscanCount
, overscanColumnsCount
, and overscanRowsCount
for grid component. (Use overscanColumnCount
and overscanRowCount
instead.)overscanCount
will be removed for list components, in favor of a dynamic overscanning approach.direction
. (These were moved to layout
, but they will be removed entirely in version 2.)itemData
prop (and the corresponding data
prop passed to item renderers) will be removed because the change to a render prop API no longer make this necessary.useIsScrolling
prop (and the corresponding isScrolling
prop passed to item renderers) will be removed because the changes to pre-rendering and display locking would make this more expensive to implement.Note that some of the above deprecated props may not still be relevant given the other planned changes, but I'm listing them here anyway for completeness sake.
Horizontal lists are widely used on mobile in our case. We are use them for infinite scrollable carousel like control too. IMO must have thing on mobile.
Thanks for sharing a use case @istarkov. It's not that I don't think there are _any_ valid use cases for horizontal windowing. I just think they are far less common. (Even in the case of carousels, many use left/right arrow navigation that doesn't require "scroll" event based windowing.) I think it might still be the better route (for me) to drop support for v2 to help offset some of the complexity I'm planning on introducing with pre-rendering, dynamic sizing, etc.
I'm really excited for this leaner approach that will hopefully lead to simpler, more performant, and simpler code.
Great. But I have few concerns about dropping variable size list. You are planning to replace variable size list with DynamicList but the issue with dynamic list that you can't scroll to item, which might be pretty useful feature for some components and such requirement could came up over time, so you can't predict if react-window fits your needs.
The second issue I see is dynamic list performance, if you can provide the same performance for dynamic list as for variable size list it might be ok to drop it even if you won't support scrollToItem, but if not, developers could be locked in weird situations where Dynamic list is slow and has no scroll to item support, List has only fixed items height.
You are planning to replace variable size list with DynamicList but the issue with dynamic list that you can't scroll to item
I don't think this is an inherent limitation, just one of the current implementation. I have ideas for how I could offer that function. Whether I find time to tackle it is another question :smile:
The second issue I see is dynamic list performance, if you can provide the same performance for dynamic list as for variable size list it might be ok to drop it even if you won't support scrollToItem, but if not, developers could be locked in weird situations where Dynamic list is slow and has no scroll to item support, List has only fixed items height.
Hard to say if it will perform as well. Seems like dynamic list will have to do more work so it's probable that it won't perform quite as well. Maybe the difference will be significant, maybe not. I want to be able to support some things I don't currently, and I think I need to cut scope to add new features. If you're currently happy with variable list though, there's no reason to upgrade to v2 (at least any time soon).
@bvaughn This looks like documentation to me!
Have you been working on this since last summer? ;-)
On a more serious note - I think render props make sense in this context, even though I'm not a fan.
No, I wrote this this morning 😝 I'm exhausted.
I think render props make sense in this context, even though I'm not a fan.
Can you elaborate why you're not a fan?
Could horizontal list/grid support make sense as an opt in feature like AutoSizer
(react-virtualized-auto-sizer) ?
I've used both react-virtualized and react-window for horizontal lists, and find the react-window API a lot simpler. Though I def understand the need for the deprecation in hopes for a simpler API.
Grid support is still planned. Opt in horizontal support, no not really. I don't think that would make sense.
@bvaughn I generally enjoy render props and they will solve the problems you've outlined, but I I think they encourage an inline function which may or may not contain a bunch of nested logic. 🤔 Any fault here falls on the user though. 🙂
can you realize masonry grid?
@nikitapilgrim No. I would suggest just using the Masonry
component from react-virtualized
https://github.com/bvaughn/react-virtualized/blob/master/docs/Masonry.md
thanks, but its work only with react-virtualized?
@nikitapilgrim Yup. 👍
React-virtualized supports a bunch of features, that react-window does not.
The scope of react-window is drastically reduced, to focus on making the package smaller and faster. 😉
If you need features from react-virtualized, I suggest you stick with that - it's still a great a library!
I stumbled upon react-window
because I was looking for a solution to this react-virtualized
babel 7
issue. I am using the react-virtualized
Masonry
components but can't anymore after upgrading babel
.
This isn't the place to report issues with react-virtualized.
Agreed @bvaughn. However yourself and @babangsund replied to @nikitapilgrim above that a Masonry
component won't be introduced in react-window
and instead to use react-virtualized
. However, if a user is on the latest [email protected]
and [email protected]
(such as with create-react-app
), react-virtualized
won't necessarily work.
I figure that is useful info for anyone else going down the same rabbit hole.
¯\ _ (ツ) _ /¯
hey i want to use dynamic size list where can i download version 2 or i will have to use react virtualise ?
this is how my list is looking with variable size list
This is not a generic support issue. Please keep comments on topic.
Feedback is appreciated
I'm using react-window
on a trello-like product and here's some thoughts:
Render props
This seems like a good change because of the simplicity and to avoid the mentioned downside. Also, the api would be more similar to react-native's FlatList. I remember reading the discussion at https://github.com/bvaughn/react-window/issues/85.
Fewer components
No more horizontal list support
I highly vote against the removal of horizontal
support and VariableSizeList
. As you can imagine, these are the main two that I use. Are their implementation really too much of a burden to maintain? If not, I hope you can reconsider and keep them.
I don't have any strong opinions related to the other changes. The overscanCount
removal does worry me a little but I've not faced use cases where a custom value was required yet, so it's probably fine.
Hey @bvaughn! Thanks for this package! I'm looking to incorporate version 2 in my project at work. Do you have a ballpark on when this might be released?
Thanks for this library, and sharing your plan for future release it's very helpful to help us mitigate technical debt.
Is there a "simple" way to have WindowScroller
behavior using the recent react-window
and later on version 2 ?
If it's not possible would this be out of the perimeter of this version 2? or could this be added later ?
My context is that my layout includes a footer, and using modern approach like DynamicSizeList
would introduce a second scroll bar (one for the page and one for the list of products)
Great package. Eagerly awaiting dynamic height lists by default -- at the moment I wrote a bunch of custom logic for passing rendered row heights back up to the parent list. Hopefully with this new version I can remove that logic. Thanks for your work on this!
@ltkn @mrdanimal
There is already a way of using window scroller:
https://github.com/bvaughn/react-window/issues/30#issuecomment-428868071
How to do Scroll infinite in both directions, left or right!!!
If we have WindowScroller
without depends on react-virtualized
that will be great. Because the goal behind react-window
made it much efficient and less code comparing to react-virtualized
So, I don't want to use WindowScroller
from react-virtualized
. Instead looking for a separate package like react-virtualized-auto-sizer
.
Thanks in advance.
@prabusamvel hm..
What's the advantage of a separate package?
Been playing around with the new DynamicSizeList. Very cool! I think a great enhancement would be to include 'ttb' and 'btt' (top-to-bottom, bottom-to-top) in the direction type. There is currently no clean way to implement a list that scrolls upwards, but every other direction is supported.
@toddmacintyre I can't find this version 2. Can any one guide me?
@muhammedmagdi npm install react-window@next
It would be brilliant if version 2 could support the DOM structures required by the spec here - https://www.w3.org/TR/wai-aria-1.1/#grid as #217 is still an issue for us. As far as I can tell your proposal for version 2 right now doesn't.
@mjurkowski @bvaughn yarn add react-window@next
installs 1.6.0-alpha.1
. Also when trying to run the dynamic list sandbox example https://react-window-next.now.sh/#/examples/list/dynamic-size it throws Error importing GitHub repository: Could not find package.json
How about passing the index
in Grid as well - while at it?:)
Part of our application requires a grid with variable width column headers. We've achieved that by using a horizontal variable sized list coupled with a grid and synchronising the scrolling of the two.
Removing horizontal lists will prevent us creating that UI (or at least we'll have to re-write it to use 2 grids where the column header grid has a single row.
Next product looks amazing. But I need both horizontal and vertical, so FYI I created my own: https://www.npmjs.com/package/react-infinite-grid-scroller. Uses grid layout, react hooks, IntersectionObserver, and requestIdleCallback.
Feedback welcome.
I have the feeling that supporting sticky elements would be a great addition to react-window. It is a pretty common use case and would be straight forward to implement for both lists and grids.
The API could look like this:
<Grid
// First 2 columns are sticky
stickyLeft={2}
// Last column is not sticky (default value)
stickyRight={0}
// First and last rows are sticky
stickyTop={1}
stickyBottom={1}
/>
The two key elements to make the stickiness work are:
position: sticky
instead of absolute
, and use margin-x
instead of left
and top
for the axis that is not stickyThe cost of such a great feature seems reasonable:
position: sticky
just see a normal version If you think this use case is too specific to be supported as is, a great compromise would be to support only point 1. Being able to specify whether or not a cell should be rendered would allow to implement stickiness easily.
I would be glad to help if needed.
does not support automatically measuring and updating their sizes.
I feel like this is a pretty big down side. For almost every grid I've written I need to have 3 or 4 fixed width columns (for a status label, some meta data, a call to action etc) and 1 dynamic width column that takes up the rest of the available space.
I appreciate that "does not support" doesn't necessarily mean this won't be possible with the addition of additional code and components like Autosizer - it would just be nice to have those use cases well considered and solutions documented for those that need a dynamic column but don't want to go to react-virtualized for all the baggage it brings with it.
it would just be nice to have those use cases well considered and solutions documented for those that need a dynamic column
Totally understood- but practically speaking, that would require a lot of effort, and this library has been a labor of love (not a paid endeavor). Unfortunately I haven't even had time to finish my scoped down v2 efforts, let alone anything more aggressive. 😞
it would just be nice to have those use cases well considered and solutions documented for those that need a dynamic column
Totally understood- but practically speaking, that would require a lot of effort, and this library has been a labor of love (not a paid endeavor). Unfortunately I haven't even had time to finish my _scoped down_ v2 efforts, let alone anything more aggressive. 😞
Yup. I get that. Hopefully those kind of efforts can be community led.
Would be nice- but in my experience, that never happens :smile:
I have been unable to use WindowScroller
with DynamicSizedList, probably because of the just-in-time rendering making scrollTo not work very well. Will this be possible with the new version?
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 #6 for details on the List
and Grid
should be implemented to support just-in-time measurements.)
Hi @bvaughn,
I have created a discussion on my fork with some random notes.
Let me know if there's anything that should not be on the list or that is not correct. I'll complete the list when I'll make progress.
Looks like good stuff
Most helpful comment
Horizontal lists are widely used on mobile in our case. We are use them for infinite scrollable carousel like control too. IMO must have thing on mobile.