Skip to content
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

Version 2 changes #302

Closed
bvaughn opened this issue Jul 29, 2019 · 47 comments
Closed

Version 2 changes #302

bvaughn opened this issue Jul 29, 2019 · 47 comments
Labels
💬 discussion 👋 help wanted Extra attention is needed

Comments

@bvaughn
Copy link
Owner

bvaughn commented Jul 29, 2019

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.


Table of contents:
  • Support fewer components
  • Use render props API
  • No more horizontal lists support
  • Only grids support RTL
  • Changes to onScroll callback timing
  • Other changes/deprecations

Fewer components

One 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)
    • This highly optimized list component should be used when row heights are fixed (and known ahead of time).
  • List (previously DynamicSizeList)
    • This list should be used for dynamically sized content (e.g. chat, newsfeed). It requires the ResizeObserver API (or polyfill).
  • Grid (previously VariableSizeGrid)
    • This component should be used for tabular data (e.g. spreadsheets) that should be virtualized along both vertical and horizontal axis. It supports variable size rows and columns, but does not support automatically measuring and updating their sizes.

Render props

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 provides built-in solutions for memoization (e.g. React.memo, useMemo, shouldComponentUpdate) so I didn't need to implement my own caching abstraction for item renderers.
  • APIs like hooks and suspense "just work" inside of item renderers.
  • Keys can be managed by react-window without requiring the render prop to pass them along (and without requiring cloneElement calls).

Unfortunately there were also some downsides:

  • Inline item renderers incur a high cost. Because their "type" (the function definition) gets recreated each time the parent component renders, React deeply unmounts and remounts their rendered tree. This means that docs need to teach people not to use them even though they're often more convenient.
  • Because inline functions couldn't be used to close over local scope, it was more complicated for item renderers to share state with parents, requiring APIs like 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}
  />
);

No more horizontal list support

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".


RTL support

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 changes

List 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.


Other props changes/deprecations

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.
  • "horizontal" and "vertical" values for direction. (These were moved to layout, but they will be removed entirely in version 2.)
  • The 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.
  • The 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.
  • Scroll align parameters will change slightly. The previously named "auto" will now be named "minimal". The new default value will be "smart" (rather than "auto").

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.

@bvaughn bvaughn changed the title Version 2 umbrella Version 2 changes Jul 29, 2019
@istarkov
Copy link
Contributor

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.

@bvaughn
Copy link
Owner Author

bvaughn commented Jul 29, 2019

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.

@chrisnojima
Copy link

I'm really excited for this leaner approach that will hopefully lead to simpler, more performant, and simpler code.

@zmitry
Copy link

zmitry commented Jul 29, 2019

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.

@bvaughn
Copy link
Owner Author

bvaughn commented Jul 29, 2019

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 😄

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).

@babangsund
Copy link

babangsund commented Jul 29, 2019

@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.

@bvaughn
Copy link
Owner Author

bvaughn commented Jul 29, 2019

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?

@snesjhon
Copy link

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.

@bvaughn
Copy link
Owner Author

bvaughn commented Jul 30, 2019 via email

@babangsund
Copy link

babangsund commented Jul 30, 2019

@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. 🙂

@nikitapilgrim
Copy link

can you realize masonry grid?

@bvaughn
Copy link
Owner Author

bvaughn commented Jul 30, 2019

@nikitapilgrim No. I would suggest just using the Masonry component from react-virtualized

https://github.com/bvaughn/react-virtualized/blob/master/docs/Masonry.md

@nikitapilgrim
Copy link

thanks, but its work only with react-virtualized?

@babangsund
Copy link

@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!

@wallzero

This comment has been minimized.

@bvaughn
Copy link
Owner Author

bvaughn commented Aug 13, 2019

This isn't the place to report issues with react-virtualized.

@wallzero

This comment has been minimized.

@ShivamJoker

This comment has been minimized.

@bvaughn
Copy link
Owner Author

bvaughn commented Aug 17, 2019

This is not a generic support issue. Please keep comments on topic.

@brunolemos
Copy link

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 #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.

brunolemos added a commit to devhubapp/devhub that referenced this issue Aug 27, 2019
Hopefully this feature doesn't get removed from react-window bvaughn/react-window#302
brunolemos added a commit to devhubapp/devhub that referenced this issue Aug 28, 2019
Hopefully this feature doesn't get removed from react-window bvaughn/react-window#302
This was referenced Sep 4, 2019
@chippawah
Copy link

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?

@ltkn
Copy link

ltkn commented Sep 20, 2019

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)

@galbeiroc
Copy link

How to do Scroll infinite in both directions, left or right!!!

@prabusamvel
Copy link

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.

@PascalSenn
Copy link

@prabusamvel hm..
What's the advantage of a separate package?

@toddmacintyre
Copy link

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.

@ghost
Copy link

ghost commented Jan 23, 2020

@toddmacintyre I can't find this version 2. Can any one guide me?

@mjurkowski
Copy link

@muhammedmagdi npm install react-window@next

@MarkFalconbridge
Copy link
Contributor

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.

@mdegrees
Copy link

mdegrees commented Feb 4, 2020

@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

@phaistonian
Copy link

How about passing the index in Grid as well - while at it?:)

@MarkFalconbridge
Copy link
Contributor

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.

@HenrikBechmann
Copy link

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.

@nick-keller
Copy link

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:

  1. only unmount cells that are sticky if they are out of the window in the axis they are not sticky
  2. use position: sticky instead of absolute, and use margin-x instead of left and top for the axis that is not sticky

The cost of such a great feature seems reasonable:

  • The footprint is minimal
  • No major impact on performance (just rendering a few extra rows / columns)
  • Browser support is great, and those that do not support 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.

@slashwhatever
Copy link

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.

@bvaughn
Copy link
Owner Author

bvaughn commented Jul 28, 2020

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. 😞

@slashwhatever
Copy link

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.

@bvaughn
Copy link
Owner Author

bvaughn commented Jul 28, 2020

Would be nice- but in my experience, that never happens 😄

@tastyqbit
Copy link

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?

@bvaughn
Copy link
Owner Author

bvaughn commented Dec 4, 2020

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.)

@bvaughn bvaughn added the 👋 help wanted Extra attention is needed label Dec 4, 2020
@pfongkye
Copy link

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.

@bvaughn
Copy link
Owner Author

bvaughn commented Dec 14, 2020

Looks like good stuff

@LorenDorez
Copy link

@bvaughn So where are we with things here? Is there going to be a v2? Not complaining just love the plugin and wanted to get a sense of current state and potentially where things stand. Would like to help if i can

@akshit-mt
Copy link

akshit-mt commented Sep 26, 2022

@bvaughn do we have support for cell merging in VariableSizeGrid using react-window, I believe this is a big requirement for many.
Is there any other package that can be leveraged for the same?

@impauloalves
Copy link

@bvaughn do we have support for cell merging in VariableSizeGrid using react-window, I believe this is a big requirement for many. Is there any other package that can be leveraged for the same?

@bvaughn any idea on how to implement this? @akshit-mt were you able to find a solution?

@bvaughn bvaughn closed this as completed Aug 13, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
💬 discussion 👋 help wanted Extra attention is needed
Projects
None yet
Development

Successfully merging a pull request may close this issue.