React-window: Support just-in-time measured content

Created on 30 May 2018  ·  132Comments  ·  Source: bvaughn/react-window

In order to avoid adding cost to existing list and grid components, create a new variant (e.g. DynamicSizeList and DynamicSizeGrid). 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:

  1. Content is measured only if no current measurements exists.
  2. Measurements need to be reset externally (imperatively) if something changes.
  3. Cells at a given index can only be positioned after all cells before that index have been measured.

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.

screen shot 2018-06-10 at 11 58 38 am

  • When scroll position changes, if the delta is less than the threshold, choose which new items to render relative to the anchor index. Position these items relative to the previously positioned items. Continuing with the example above, if the list was scrolled by a small amount (200px) then 200px worth of additional rows would need to be appended below the previously positioned items:

screen shot 2018-06-10 at 12 01 01 pm

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.
    screen shot 2018-06-10 at 5 04 42 pm

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.
screen shot 2018-06-10 at 5 08 26 pm

👋 help wanted

Most helpful comment

There is no "you guys" on this project. It's maintained by a single person.

And it's kind of inconsiderate to leave comments on multiple issues in the same day complaining about the same thing. By all means, please just use react-virtualized.

All 132 comments

I use this within mui-downshift and currently still use UNSAFE_componentWillReceiveProps, although I plan to try to port to react-window in the near future (once the dynamic content height is available).

is this a reusable mechanism in UITableView in IOS ?

@luoboding I don't understand your question. Could you elaborate?

@bvaughn sorry, my friend, my english is not very good.

i have a problem in my project, i have thousands of options in select element, it get very slow and jammed when page reload, i tried to write a component to make it better, i was a IOS developer, i know a reusable mechanism in UITableView in IOS, if i need a 500px height select element, i configure option-element's height to 100px, so i just need create (Math.floor(500 / 100)) number of option element and capacity of queue(current displayed datasource queue), when i scroll select element up or down, just push or pop into the queue to re-render it.

i want import react-window in my project, does it work like i mentioned?

What you're describing is how react-window (and windowing, or occlusion culling, in general) works. It's not really related to this issue though. This is about just-in-time measuring the windowed content. In your case, objects have a fixed height– so you can use the FixedSizeList component: https://react-window.now.sh/#/examples/list/fixed-size

Nice to see anchoring natively addressed in react-window.

By the way sorry if I raised the bar a little bit too much on diagrams… 😅

@bvaughn when will you release this feature, I'm looking for that

I published 1.0.0 without this functionality because I'm having trouble finding the time (and energy) to finish this right now. Still plan to add it in the future. No estimate on when.

Looks like Polymer's "iron list" uses a similar technique as what I'm proposing here: https://github.com/domenic/infinite-list-study-group/blob/master/studies/Polymer-iron-list.md#virtual-list-sizing

this would be really useful for us, right now it seems like we have to keep CSS in sync with component logic that duplicates the height computation just to pass it to the virtual list.

@kevinder can you share how you are addressing just-in-time measured content? Thanks in advance

@carlosagsmendes not sure if this will help but here is what I am doing when using this to display chat history:

1.) In the constructor create a ref for the list and for my ChatHistory component:

  constructor(props) {
    super(props);
    this.listRef = createRef();
    this.chatHistoryRef = createRef();
    this.listHeight = 0;
  }

I then pass the refs down to the ChatHistory which is responsible for rendering the list

2.) In componentDidMount of the parent component I use the ChatHistory ref to get the height of the element:

componentDidMount() {
    this.listHeight = this.chatHistoryRef.current.offsetHeight;
}

3.) In the parent component I maintain an array in it's state with the chathistory details. When adding a new item to that array I do it like this:

  // find out how many pixels in height the text is going to use
  const size = getSize({
    text: displayText,
    className: styles.message,
  });

  let { height } = size;
  height += 20; // adds some spacing in pixels between messages
...rest of items needed for the chat history item..add them all to an array and update state

getSize is based on https://github.com/schickling/calculate-size but I modified it to support accepting a class name. That class is the same one used as the container for displaying the individual messages

I'm sure there's a better way to achieve this but it seems pretty fast and I haven't hit any issues yet

@osdlge: Any chance you have a demo of this anywhere I could check out– like Code Sandbox (or similar)?

@bvaughn sure thing, I extracted the relevant parts of my code to https://codesandbox.io/s/5z282z7q1l

Thank you for sharing! 😄

I've pushed some work in progress to an initial approach on lazily measured content to a branch named issue/6

I've also deployed a demo:
https://react-window-next.now.sh/#/examples/list/dynamic-size

Very cool.

I'm still trying to make sense of the general problems with infinite scrolling while going through the issue/6 branch source and this discussion. So the question following question may not make sense, but here it goes since I would really like to understand this further:

Is the above mention to 'Scroll Anchor' related to scroll Anchoring as a technique like in the linked article or the CSS Scroll Anchoring specification?

Thanks in advance

It's kind of tangentially related to your first link, but not to the second one. It's just a term I chose to use for the issue because it made sense to me, not because it's related to any other spec or proposal.

I've also published a pre-release version of react-window to NPM as "next" (e.g. yarn add react-window@next).

You can play around with it by forking this Code Sandbox:
https://codesandbox.io/s/5x8vlm0o7n

I just tested it out. I tried 10000 paragraphs and tried to jump to the end. It was jerky.
If I understood correctly, it should have only measured the rows estimated to be at the end an therefore it should have jumped instantaneously to the end. Is this correct?

On 12 Oct 2018, at 12:53, Brian Vaughn notifications@github.com wrote:

I've also published a pre-release version of react-window to NPM as "next" (e.g. yarn add react-window@next).

You can play around with it by forking this Code Sandbox:
https://codesandbox.io/s/5x8vlm0o7n https://codesandbox.io/s/5x8vlm0o7n

You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub https://github.com/bvaughn/react-window/issues/6#issuecomment-429271555, or mute the thread https://github.com/notifications/unsubscribe-auth/AOf2h7RmSEyGmyrEdMY6GgyZFjCKlDDFks5ukGafgaJpZM4UTb3P.

No, the initial branch I've pushed doesn't implement the algorithm
described in this issue. It takes a more naive approach the requires
measuring earlier content before rendering later content.

Sorry for the confusion!

On Fri, Oct 12, 2018, 6:34 PM akraines notifications@github.com wrote:

I just tested it out. I tried 10000 paragraphs and tried to jump to the
end. It was jerky.
If I understood correctly, it should have only measured the rows estimated
to be at the end an therefore it should have jumped instantaneously to the
end. Is this correct?

On 12 Oct 2018, at 12:53, Brian Vaughn notifications@github.com wrote:

I've also published a pre-release version of react-window to NPM as
"next" (e.g. yarn add react-window@next).

You can play around with it by forking this Code Sandbox:
https://codesandbox.io/s/5x8vlm0o7n <https://codesandbox.io/s/5x8vlm0o7n


You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub <
https://github.com/bvaughn/react-window/issues/6#issuecomment-429271555>,
or mute the thread <
https://github.com/notifications/unsubscribe-auth/AOf2h7RmSEyGmyrEdMY6GgyZFjCKlDDFks5ukGafgaJpZM4UTb3P
.


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/bvaughn/react-window/issues/6#issuecomment-429282228,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AABznR5R1N0ErukleIfvaLQORF_NECgRks5ukHBHgaJpZM4UTb3P
.

Hey,
I wanted to ask if there is an estimate for an official release?

My team uses react-virtualized for a new project we started however we need the functionality of scrolling up and jumping to specific row index (as you can assume our rows have dynamic content, containing images and other changing content).

Would you recommend migrating to react-window in its alpha release? Or should we wait for an official release?

Also if there is any way i can contribute to finishing this feature i would love to help out 😄

Unfortunately I can't commit to a release timeline at the moment because I haven't done a lot of testing and I don't know what kinds of issues I'll run into when I do (or how long it will take to fix them).

If you'd like to contribute, one way would be to test the alpha release and let me know how well it works, and if you find any bugs.

I'll probably be focusing more on this soon, but I can't say how soon. Especially for the next week or two I'm distracted by React conf and getting the 16.6 release ready.

@bvaughn great work 👏 Finally have some time to play around. 🕹

It looks like we need some tweaks when hiding list with display: none For example you have page with two tabs and want to switch between them without loosing your current state ( scroll position etc.), imho it's not a rare use case.

Simple Code Sandbox presenting the issue:
https://codesandbox.io/s/p7vq18wmjq

It's happening because when we trigger display none, all children will have offsetHeight === 0
resize observes kiks in and updated's new values. react-window should not care for this situations if caller decided to hide it, basic should handle it by blocking handleNewMeasurements

if this line
https://github.com/bvaughn/react-window/blob/issues/6/src/DynamicSizeList.js#L443
would change to

handleNewMeasurements: instance._handleNewMeasurements

then we can override default logic

let _handleNewMeasurements

<DynamicSizeList  
  ref={current => {
    if (current) {
      _handleNewMeasurements = current._handleNewMeasurements
      current._handleNewMeasurements = (...args) => {
        if (!isHidden) {
          return _handleNewMeasurements(...args)
        }
      }
    }
  }}
  {...otherProps}

I pushed an update to this branch (and published a new @next tag to NPM) that fixes the Firefox smooth scrolling bug by using margin-top to account for resized items while scrolling is in progress. It's more complicated than I'd like but I don't know of a better way to handle this at the moment. (I also need to do some more testing of this approach, because I think that it might have some rough edges still in extreme cases.)

I appreciate the feedback above, @piecyk. I haven't had time to dig into it yet. (This is still kind of just a side project for me at the moment.)

Seems like I may be able to remove the margin hack in favor of scrollBy for Firefox at least. Need to test IE and Edge first though. They may have their own challenges.

Yeah @bvaughn i know, awesome work 👏 Don't know how you find the time! 🥇Kudos to you!

But let's back to the issue when the list is in some DOM element that is hidden with display none, basic we need to check if the wrapper has height, width if not we don't want to start rendering ( current it will try to render whole list ) Will try tomorrow to fix it ( have something stash )

Yup. I understand the core of the issue you're describing. I dislike the idea of hacking around it by overriding/monkey-patching more instance methods though, so I'd like to give it some more thought first.

Seems like the @next package is broken?

https://codesandbox.io/s/5x8vlm0o7n

Don't know if that's the proper place to leave a question, so excuse me if I'm wrong. So, in short:

  • I've used DynamicSizeList along with AutoResizer and in general it works, nicely. Kudos!
  • I've been asked to introduce Rows whose content can expand (adding an extra div with supplementary information) and retract.
  • I've also added (via redux) a prop on these Rows that listens for global expand/retract actions.
  • Fun stuff starts. I click expand/retract and everything looks great!
  • If I scroll a little and then expand/retract all the rows, the number of retracted rows is the same as to that of the expanded rows. If I expand retract again, number goes to half and so on.
    (i.e. 30 rows retracted -> 10 expanded ->click retract -> 10 rows retracted -> click expand -> 3 rows expanded -> click retract -> 3 rows retracted).

I tried to reload the itemData by supplying a different yet same object with the JSON.parse(JSON.stringify(data)) hack. No luck :-(

I suspect a miscalculation of the height. Any idea to overcome this issue?

Could you share a codesandbox example? I need to do something similar so maybe we can help each other

@vtripolitakis I've just found an example with expandable rows. Here's the link to the discussion

@carlosagsmendes thanks for this, but my case study is a little different as I use the the DynamicSizeList :-(

So I found the reason of the issue:
state.scrollOffset was taking negative values.

on src/DynamicSizeList.js we need to add the following code on line 299

if (sizeDeltaForStateUpdate < 0) {
          sizeDeltaForStateUpdate = 0;
        }

Hm... I wouldn't expect that fix to be right, at a glance. A size delta might legitimately be negative, no?

Maybe we should have a guard (Math.max(0, prevState.scrollOffset + sizeDeltaForStateUpdate)) around where the state.scrollOffset value is updated?

Hello, as I debugged my case sizeDeltaTotal took negative values and accordingly made sizeDeltaForStateUpdate negative, yielding a negative state.scrollOffset after state update.

This happened when I expanded and retracted items and then scrolled to the top having scrollOffset 0 and direction backwards. Then If I expand and retract a few times, I got the negatives.
Yes, your suggestion should be equally good. ~Testing it right now.~ Works properly.

@marcneander try version 1.4.0-alpha.1

Regarding ignoring resize events when list is hidden, maybe something like this https://github.com/piecyk/react-window/commit/acfd88822156611cfd38872acdafbbefd2d0f78f
@bvaughn what do you think ?

I'm trying to add auto-scroll in a chatbox-style app and I'm running into this issue: DynamicSizeList does not support scrolling to items that have not yet measured. scrollToItem() was called with index 111 but the last measured item was 110.

I'm trying to call scrollToItem(items.length-1) in componentDidUpdate

Is this intended behavior?

Yeah, maybe something like that could work @piecyk 👍

Is this intended behavior?

Doesn't sound like it @xaviergmail, no. Maybe a bug.

hey @bvaughn I don't mean to derail this issue, but I wanted to chime in to say that there's a neat sparse array implementation from the Flex 4 DataGrid internals that may be able to help here. I know Flash is :-1:, but the last version of Flex actually had a pretty great virtualized layout engine... because Flash :-)

The LinearLayoutVector is a sparse array for mapping between item indices and pixel positions in a single dimension. The three basic operations are:

interface LinearLayoutVector {
   start: (index) => position;
     end: (index) => position;
  indexOf: (position) => index;
}

Internally it allocates buckets in powers of 2 for storing item positions (the specific power can be tuned to better accommodate larger or smaller item sizes). This enables constant-time O(1) index -> position lookups, and an efficient linear block scan for position -> index lookups. It supports padding, gaps, default sizes, and random-access insertion, removal, and updates.

I ported it to JS about 6 years ago when I was doing a lot of virtualized UIs for mobile. It could use an update to ES6 for readability, and could probably squeeze out more speed by switching to typed arrays, but the basic logic is sound.

I submitted a draft PR to react-virtualized a few weeks back that switched out the internals of CellSizeAndPositionManager with the LLV and it did solve a few perf/cache invalidation things. If you're down, I'd be happy to submit a similar PR to react-window in the next few weeks.

Hi @trxcllnt 👋

If you'd be interested in sharing a PR, I'd be happy to take a look. You would want to make it against the issues/6 branch (WIP PR #102).

At a glance, linear-layout-vector doesn't look like it's got any tests or being used too heavily, so I would have a little bit of initial reluctance but I'd still be willing to take a look. I'd also want to look at how much weight it adds to a bundle after being uglified+minified but I wouldn't expect it to add too much. 😄

@bvaughn no sweat, I totally understand. It was a thing I did years ago over xmas IIRC. I'll clean it up and ensure it lands with a full test suite. Don't worry about incurring an extra dependency either. It's such a small class, I'm happy to contribute it directly.

After I commented, I remembered I had the demo I did the port for: https://github.com/trxcllnt/virt-list. Hit up that GH pages site and throw the movies list left and right (this was related to some discussions about render perf we were having in the iOS team at Netflix).

@bvaughn Thank you for all of the work that has gone in the issues/6 branch for the past year!
I am currently testing ^1.6.0-alpha.1 and plan on shipping to production with that version.

Thought I'd post what I needed to do in order to work with the new DynamicSizeList for anyone else looking at this issue and using the latest on the branch.

Following the docs linked above and those generated from the issues/6 branch will lead to

Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?

and so the fix was to imitate what you do in tests and...

import { DynamicSizeList as List } from 'react-window';
import AutoSizer from 'react-virtualized-auto-sizer';

// in constructor(props) for handling scrolling
this.listRef = React.createRef();

// in render()
const allItems = [...];
const Renderer = ({ forwardedRef, style, index, ...rest }) => (
  <div ref={forwardedRef} style={style}>
    <MyCoolComponent index={index} otherProps={otherPropsBasedOnAllItems} />
  </div>
);

const RefForwarder = React.forwardRef((props, ref) => (
  <Renderer forwardedRef={ref} {...props} />
));

return <div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
  <div style={{ flexGrow: 0, flexShrink: 0, width: '100%', position: 'sticky', top: 0, zIndex: zIndexHideLayers }}>
    <MyCoolComponentThatControlsScrolling listRef={this.listRef} />
  </div>
  <div style={{ flex: 1, width: '100%' }}>
    <AutoSizer>
      {({ height, width }) => (
        <List ref={this.listRef} itemCount={allItems.length} width={width} height={height}>
          {RefForwarder}
        </List>
      )}
    </AutoSizer>
  </div>
</div>;

My example probably includes more than what you'd want on that docs page, but hopefully will make the doc update easier for you

Feedback on the current version of the branch?
💯 works well
🎉 thanks again for all the work!

edit: DynamicSizeList seriously makes this library so easy to use now.

Thanks for sharing the details! When I get some bandwidth to pick this issue back up, I'll dig into them.

I think this approach may be usable along with the original proposal in this issue.

Rather than using the item's previous size, we could just use the estimated sizes– and refine with actual sizes as someone scrolls. (I don't think there's an important distinction between "previously measured size" and "estimated size" except for the fact that the previously measured size is likely to be more accurate. Still, this might be an acceptable trade off since it would allow us to jump to arbitrary places in the data without rendering things that came before, _and_ it would free us up from having to maintain an item size cache.)

I think this could simplify the scroll anchoring problem significantly. We could just do the initial jump (as described) and then pretend everything "before" (above or left) was exactly the estimated size. Then as we scroll, refine.

Could maybe work?

@bvaughn Will this fix the issue that @xaviergmail addressed, with initially scrolling to the "bottom" like a chat? I created a codesandbox of an example of it not working. If not, are there any workarounds?

https://codesandbox.io/s/vr648ywy3

Let's keep the comments on this issue focused on API discussion, not troubleshooting.

I suggest Stack Overflow for asking questions.

Is it possible to expose the resetAfterIndex in this API? I add, edit, and remove from my DynamicSizeList and, at least from what I can gather, this would be the method to call to fix heights up, yes?

@bvaughn was playing around over the weekend with the idea position the items with anchor index and scrolling the list to align what user is seeing... First impressions that it could work 😅 For simplicity the list is rendered without any overscan elements, also we need change how cache is working ( in this wip it's cleared always ) ... What do you think ?

poc implementation https://github.com/piecyk/react-window/pull/2/files
here is the code sandbox running the build of the branch
https://codesandbox.io/s/4x1q1n6nn9

uh-oh firefox can't keep up with rendering when fast scrolling like chrome does using this approach 🤷‍♂️

I'm trying to add auto-scroll in a chatbox-style app and I'm running into this issue: DynamicSizeList does not support scrolling to items that have not yet measured. scrollToItem() was called with index 111 but the last measured item was 110.

I'm trying to call scrollToItem(items.length-1) in componentDidUpdate

Is this intended behavior?

Kinda late but I'm trying to solve that problem with this react hook.

Not the best solution but I'm still working on it. Maybe we can work to make it more generic (and simple) and create a package?

Gif to show how this is working right now:
https://cl.ly/87ca5ac94deb

Maybe we can open a new issue to talk about a solution for this chat-like behaviour?

uh-oh firefox can't keep up with rendering when fast scrolling like chrome does using this approach

Looks like it works in Firefox Nightly version 68.

@bvaughn I am using the DynamicSizeList with the InfiniteLoader and Autosizer components to try to create a feed. I like what I am seeng so far, keep it up :)

In terms of API and behavior:

  1. Can we get the data object as a second argument in the itemKey callback, the way it is in the FixedSizeList?

  2. Can we reset the the inner container height when the data object is filtered/modified.

I've been using DynamicSizeList from 1.6.0-alpha.1 with InfiniteLoader for a while now and it has been working great. Thanks for the awesome feature!

However, now I have a requirement to use scrollToItem(). Similar to an above comment, but distinct because nothing at all is measured yet, I get:

DynamicSizeList does not support scrolling to items that yave not yet measured. scrollToItem() was called with index 9 but the last measured item was -1.

It doesn't appear to be timing related as I tried calling it after a long setTimeout. So, can I force a measurement? Or are there any workarounds?

EDIT: Nevermind, initialScrollOffset did what I needed.

why use findDOMNode?

Do type definitions exist for the @next branch?

@WillSquire no, they do not. I'm also unsure if it's possible to release them at @next tag in DefinitelyTyped (I might be mistaken). Also, I think it would be better to wait till this branch is finally merged and new version released since API could still change.

@bvaughn I've been willing to use this at devhub, but before I invest on integrating it do you think it's already on good shape or still has some blocker issues?

@brunolemos My todo list on #102 is pretty accurate I think. If you've tested and feel like it's in a good shape for the browsers you're targeting, then keep me posted!

keep me posted!

~Tried to use it but haven't succeed so far.~

Got it working but performance is not good. Maybe my item renders are expensive or other thing.

https://github.com/devhubapp/devhub/pull/152

It looks like something may have broke in the latest version when using AutoSizer with a container height of 100%

Edit: I was able to find a workaround using 100vh and calc()

something may have broke

Too vague to be actionable. Share a repro along with expected behavior?

I am using DynamicSizeList from 1.6.0-alpha.1 with different filters and some complex card view. But we need to wrap with the hight and width. It is working fine for me.

Thank you Guys

Hello, I'm trying out DynamicSizeList, but all my items are rendered on top of each other. I do pass the style attribute to the rendered item, but if i log style, i see that height is undefined for each item, top and left are always 0.
What did I miss here :-) ?

@graphee-gabriel you miss a reproduction example.

Height is intentionally not specified initially, in order to let the items render with their natural size...

Ok I do understand the logic, then this is not the reason the items are rendering on top of each other.
I will provide as much data as I can, I thought that maybe i made a common mistake or missed an obvious step that leads to this issue (such as not passing down the style object).

Screen Shot 2019-07-07 at 18 08 53

import React from 'react'
import { DynamicSizeList as List } from 'react-window'

import Layout from '../Layout'
import Text from '../Text'
import withScreenDimensions from '../withScreenDimensions'

class ListView extends React.Component {
  state = {
    availableHeight: 0
  }

  componentDidMount() {
    const checkForHeightChange = () => {
      if (this.containerDiv) {
        const { offsetHeight } = this.containerDiv
        if (this.offsetHeight !== offsetHeight) {
          this.offsetHeight = offsetHeight
          this.setState({ availableHeight: offsetHeight })
        }
      }
    }
    checkForHeightChange()
    this.intervalId = setInterval(checkForHeightChange, 10)
  }

  componentWillUnmount() {
    clearInterval(this.intervalId)
  }

  render() {
    const {
      data,
      renderItem,
      emptyText,
      dimensions,
    } = this.props
    const { width } = dimensions
    const { availableHeight } = this.state
    return (
      <Layout
        centerVertical
        style={{
          height: '100%',
        }}>
        {data && data.length > 0 ? (
          <div
            style={{
              display: 'flex',
              flex: 1,
              height: '100%',
              backgroundColor: 'red',
              alignItems: 'stretch',
              justifyContent: 'stretch',
            }}
            ref={ref => this.containerDiv = ref}
          >
            <List
              height={availableHeight}
              itemCount={data.length}
              width={width > 800 ? 800 : width}
            >
              {({ index, style }) => {
                console.log('style', style)
                return (
                  <div style={style}>
                    {renderItem({
                      item: data[index], index
                    })}
                  </div>
                )
              }}
            </List>
          </div>
        ) : (
            <Text bold center padding accent>{emptyText}</Text>
          )}
      </Layout>
    )
  }
}


export default withScreenDimensions(ListView)

Share a Code Sandbox where I can see this?

I would suggest _not_ using an inline function for your item renderer because it causes unnecessary remounts due to the fact that it changes each time the parent is rendered. (This is why all of the examples avoid inline functions.)

@graphee-gabriel I've had this as well, the docs don't mention it but you need to make your row component support receiving a ref:

Row = React.forwardRef(
      (row, ref) => (
        <div ref={ref} style={row.style}>
          {renderItem({
            item: data[row.index],
            index: row.index,
          })}
        </div>
      ),
    )

Hello, here you go:

https://codesandbox.io/s/sweet-sea-irxl8?fontsize=14

Yes indeed for the inline functions, it's a really old code i tried to migrate to react-window, and didn't take the time to improve it here as well.
Thanks for your feedback. Let me know what you find in this sandbox.

Annnnnd I should have checked @brunolemos message before doing that sandbox hehe.
This was the missing step, and fixed my issue, thank you!

It raised another issue, I updated the sand box so you can reproduce @bvaughn
Find it here: https://codesandbox.io/s/sweet-sea-irxl8

Now the list works fine, but weirdly it seems to grow with the content, and never shrinks again.

Meaning:

  1. If I show 6 items, scroll until the end, everything is fine.
  2. Change the content to show 20 items, scroll until the end, all good.
  3. Change back the content to 6 items, scroll until the last item, but I can continue scrolling on white space that seems to be left from the previous content (the 20 item data set).

It raised another issue, I updated the sand box so you can reproduce @bvaughn
Find it here: https://codesandbox.io/s/sweet-sea-irxl8

Now the list works fine, but weirdly it seems to grow with the content, and never shrinks again.

Meaning:

  1. If I show 6 items, scroll until the end, everything is fine.
  2. Change the content to show 20 items, scroll until the end, all good.
  3. Change back the content to 6 items, scroll until the last item, but I can continue scrolling on white space that seems to be left from the previous content (the 20 item data set).

I am having the same issue

This is exactly what I needed.
I have just tested the DynamicSizeList from 1.6.0-alpha.1 in combination with react-virtualized-auto-sizer and react-window-infinite-loader with very good results.
Anything I can help with to make this move forward?

Hello @bvaughn, did you have time to check the codesandbox from https://github.com/bvaughn/react-window/issues/6#issuecomment-509213284 ?

Hi, I'm using DynamicSizeList for my chat app.
Thanks for the awesome feature.

However, I have problems with poor performance and lots of script processing.
When scrolling, CPU always rises and often reaches 100%.
Do you have any ideas for solutions?

import { useChatList } from '../../../hooks/chat/useChatList';
import LoadingSpinner from '../../../utils/LoadingSpinner';

import dynamic from 'next/dynamic';
import * as React from 'react';
import AutoSizer from 'react-virtualized-auto-sizer';
// @ts-ignore
import { DynamicSizeList as List } from 'react-window';
import { Message } from 'src/app/typings';

const { useRef, useCallback } = React;

const RowItem = React.memo(
  ({ forwardedRef, style, index, data }: any) => {
    const item = data[index] as Message;
    if (item) {
      return (
        <div id={item.messageId} ref={forwardedRef} style={style}>
          {item.text && item.text.plainText}
        </div>
      );
    }
    return null;
  },
  (prevProps, newProps) => {
    const { index, data } = prevProps;
    const { index: newIndex, data: newData } = newProps;
    let isMemo = true;
    isMemo = isMemo && index === newIndex;
    isMemo = isMemo && data.length === newData.length;
    return isMemo;
  }
);

function ChatList() {
  const listRef = useRef<HTMLInputElement>();

  const { formatMessages: messages, isLoadingMessages } = useChatList();

  const keyCreator = useCallback((index: number) => `ChatList/RowItem/${messages[index].messageId}`, [messages]);

  if (isLoadingMessages && (!messages || messages.length <= 0)) {
    return <LoadingSpinner />;
  }
  return (
    <div style={{ flex: 1, height: '100%', width: '100%' }}>
      <AutoSizer>
        {({ height, width }) => (
          <List
            ref={(lref: HTMLInputElement) => {
              if (lref !== null) {
                listRef.current = lref;
              }
            }}
            itemCount={messages.length}
            itemData={messages}
            itemKey={keyCreator}
            height={height}
            width={width}
            overscanCount={10}
          >
            {React.forwardRef((props, ref) => (
              <RowItem forwardedRef={ref} {...props} />
            ))}
          </List>
        )}
      </AutoSizer>
    </div>
  );
}

export default ChatList;

スクリーンショット 2019-07-14 11 49 54

Hello @bvaughn, nice work!
What is correct way to recalculate item heights on resizing workplace ? With help of comments above i'm make some demo https://codesandbox.io/s/angry-hill-tcy2m
When width of workplace changing by mouse, I need recalculating all item height ( and may be clearing internal height cache of VariableSizeList component ) ...

is there any solution now for dynamic list i just spent 4 hours trying to get it working huh
after reading all the comments i am done 😠
If you guys have any working solution please provide me

There is no "you guys" on this project. It's maintained by a single person.

And it's kind of inconsiderate to leave comments on multiple issues in the same day complaining about the same thing. By all means, please just use react-virtualized.

I am really sorry for leaving comment like this brian. I found this issue later and then read all the comments and I thought others are helping you atleast

@ShivamJoker I nearly got it to work, the only thing left for it to be perfectly working is the total height that keeps growing but never shrinks after changing the content to less items. If this gets solved, in my use case it would seem to work perfectly.

@bvaughn would you have time to check the example in the sandbox from https://github.com/bvaughn/react-window/issues/6#issuecomment-509213284 ?

=> https://codesandbox.io/s/sweet-sea-irxl8

It starts with the shorter list, therefore:

  • scroll down to the end of the list
  • scroll back up and click on Show Long List
  • scroll down to the end
  • scroll back up and click on Show Short List
  • Finally scroll down one last time to see that the short list is now followed by a lot of blank spaces.

Thank you!

@ShivamJoker I nearly got it to work, the only thing left for it to be perfectly working is the total height that keeps growing but never shrinks after changing the content to less items. If this gets solved, in my use case it would seem to work perfectly.

@bvaughn would you have time to check the example in the sandbox from #6 (comment) ?

=> https://codesandbox.io/s/sweet-sea-irxl8

It starts with the shorter list, therefore:

  • scroll down to the end of the list
  • scroll back up and click on Show Long List
  • scroll down to the end
  • scroll back up and click on Show Short List
  • Finally scroll down one last time to see that the short list is now followed by a lot of blank spaces.

Thank you!

Yeah, basically the inner container should reset it's height upon data filtering/change.

@ShivamJoker I nearly got it to work, the only thing left for it to be perfectly working is the total height that keeps growing but never shrinks after changing the content to less items. If this gets solved, in my use case it would seem to work perfectly.

@bvaughn would you have time to check the example in the sandbox from #6 (comment) ?

=> https://codesandbox.io/s/sweet-sea-irxl8

It starts with the shorter list, therefore:

  • scroll down to the end of the list
  • scroll back up and click on Show Long List
  • scroll down to the end
  • scroll back up and click on Show Short List
  • Finally scroll down one last time to see that the short list is now followed by a lot of blank spaces.

Thank you!

thanks i have implemented the same hoping it to work fine for other users also
and yes i also saw that the height issue with scroll

@graphee-gabriel but I am having also one more issue my app bar used to hide on scroll down which is not happening now what can be the solution ?
image

Good day. I used DinamycSizeList in my demo project. Everything was fine, but after a while I noticed that the list component began to work incorrectly. At first I thought it was some library on which react-window depends. But looking at your demo
https://react-window-next.now.sh/#/examples/list/dynamic-size
noticed about the same result, although in the past it also worked perfectly. Could you suggest the cause of these bugs?

@simeonoff

Yeah, basically the inner container should reset it's height upon data filtering/change.

how should i do it i tried putting a state height but it doesnt seems to work
any solution ?

@simeonoff

Yeah, basically the inner container should reset it's height upon data filtering/change.

how should i do it i tried putting a state height but it doesnt seems to work
any solution ?

It must be implemented internally by the library.

@ShivamJoker I nearly got it to work, the only thing left for it to be perfectly working is the total height that keeps growing but never shrinks after changing the content to less items. If this gets solved, in my use case it would seem to work perfectly.

@bvaughn would you have time to check the example in the sandbox from #6 (comment) ?

=> https://codesandbox.io/s/sweet-sea-irxl8

It starts with the shorter list, therefore:

  • scroll down to the end of the list
  • scroll back up and click on Show Long List
  • scroll down to the end
  • scroll back up and click on Show Short List
  • Finally scroll down one last time to see that the short list is now followed by a lot of blank spaces.

Thank you!

You can set key to prevent blank spaces.
https://codesandbox.io/s/blissful-voice-mzjsc

Hello @bvaughn thank you for this awesome project!

Out of need I have been spending quite some time in DynamicLists code trying to figure out how to scroll anywhere without any limitations and how scroll to any item, measured and not.

I managed to do so here https://github.com/bvaughn/react-window/compare/issues/6...Sauco82:issues/6 by getting rid of lastMeasuredIndex and checking per item instead with itemIsMeasured, which obviously in turn requires of many other changes.

I have never participated in an open source project nor used Flow so I'm not quite sure if this is useful or worth to include, nor if I should directly try a PR or discuss it here.

I'm happy to help and tweak, so if you need anything please let me know.

Hey, here's much simpler solution (no need to append ghost elements to DOM to calculate their size):
Codesandbox

Hey, here's much simpler solution (no need to append ghost elements to DOM to calculate their size):
Codesandbox

Awesome! It works for me. Nice job.

@Kashkovsky calculated size if was update
and itemSize call once

@userbq201 @Kashkovsky great workaround! Somehow in my case it did not work out of the box, I had to modify the code of ChatHistory.js like so:

    const listRef = useRef(); // added
    const sizeMap = useRef({});
    const setSize = useCallback((index, size) => {
        sizeMap.current = {...sizeMap.current, [index]: size};
        listRef.current.resetAfterIndex(index); // added
    }, []);
    const getSize = useCallback(index => sizeMap.current[index] || 60, []);
    // ...
    <List ref={listRef}

Otherwise all items are rendered with the same default height. In your case it works as is, I can't explain why there's a difference... maybe @bvaughn can.

@bvaughn what if we have to enable similar behaviour for SSR? any hint for that side?

@bvaughn It is me or your demo is not working?

Nice implementation @Kashkovsky @kirill-konshin and @userbq201 !

How would you approach using memoization with this solution?

I tried wrapping ChatMessage in a memo with areEqual, but React still re-renders each object every time the a message is added to the list.

In my other FixedSizedLists, the memoization works fine with that memo/areEqual wrapper, but maybe the ref={root} is affecting it?

You can easily tell if React is re-rendering the components by sticking a

I forked the example here: https://codesandbox.io/s/dynamic-size-of-react-window-list-items-nb038


EDIT: I fixed the memoization - it is meant to wrap the initial functional component with memo - not the as I had done. Here is a memoized solution in case anyone has a complex DOM structure inside their lists (or if they have to map videos as I do): https://codesandbox.io/s/dynamic-size-of-react-window-list-items-errt4


EDIT 2: It turns out that the initial rendering of the rows is completely fine, but calling resetAfterIndex is very difficult to manage. My data changes (for instance when the user selects a different conversation). But the real problem is that resetAfterIndex seems to run before the new setSize can finish. So it does successfully clear the cached style, but then it just generates a new cache of the old styles again because the browser hasn't finished re-sizing the content.

Not sure if that makes sense in writing but I have to put a pin in this one for now. Please let me know if anyone is successfully changing their content dynamically and maintaining updated height styles.

I have lots of other react-window implementations so I would really prefer to find a good solution here instead of using react-virtualized for this one use case.


EDIT 3: This will be my final edit since I have finally come up with a semi-elegant solution.

1.) If the itemData needs to change (i.e. when the conversation is changing), unmount the entire component and then re-mount it with the new itemData. This can be done using a setState call back. This ensures that old height styles are not carried over when you change your data.

2.) I passed {sizeMap, setSize, listRef} to ChatMessage via ChatContext. That way, instead of just setting the size blindly, I can tell ChatMessage to set the size AND compare it to the old size. If the old size is different from the new size, then call a resetAfterIndex starting at index and passing true to force update.

So my new ChatMessage looks something like this:

const ChatMessage = ({ message, index }) => {
    const { setSize, sizeMap, listRef } = useContext(ChatContext);
    const root = React.useRef();
    useEffect(() => {
        let oldSize = sizeMap[index];
        let newSize = root.current.getBoundingClientRect().height;
        setSize(index, newSize);
        if(newSize !== oldSize){
            listRef.current.resetAfterIndex(index,true);
        }
    }, [sizeMap, setSize, listRef]);

    return (
        <div ref={root}
             {message.body}
        </div>
    );
};
export default ChatMessage;

3.) I added what is basically a listener in the component that waits for the newly mounted to be rendered. Once rendered, then it scrolls to the bottom. This fixes the problem with trying to put the scrollTo function directly in componentDidMount because it's never rendered prior to that method being called. So looks like this:

class Chat extends Component {
    constructor(props) {
        super(props);
        this.listRef = createRef();
        this.state = {
            initialScrollComplete: false,
            interval: null
        };
    }

    componentDidMount(){
        // Create interval to check if list is ready. Once ready, scroll to bottom of list.
        this.setState({interval: setInterval(()=>{
            if(this.listRef.current && !this.state.initialScrollComplete){
                this.listRef.current.scrollToItem(this.props.chatHistory.length - 1, "end");
                this.setState({initialScrollComplete: true});
            }
        },25)});
    }

    componentDidUpdate(prevProps, prevState) {

        // Clear interval if scroll has been completed
        if(!prevState.initialScrollComplete && this.state.initialScrollComplete){
            clearInterval(this.state.interval);
            this.setState({interval: null});
        }

        // If new message is transmitted, scroll to bottom
        if(prevProps.chatHistory && this.props.chatHistory && prevProps.chatHistory.length !== this.props.chatHistory.length){
            this.listRef.current.scrollToItem(this.props.chatHistory.length - 1, "end");
        }

    }

    render() {
        return <ChatHistory listRef={this.listRef} chatHistory={this.props.chatHistory}/>;
    }
}

There seems to be a really weird behaviour on safari.

The height of the DynamicSizedList div and the height or margin-top of the rows does not work correctly content starts to overlap.

When window width/content of the row changes, the new height is not recalculated or changed to work with the new height of the content.

Something that seems to fix it is if the content is scrollable, scrolling to a point where the row is not visible anymore, scrolling back up to it makes it render correctly.

The content does not render correctly on the first page load so refreshing doesn't seem to fix the problem :/

It all works absolutely fine on other browsers including chrome and firefox. Safari is aweful but unfortunately the app still needs to work for people that use it.

Screenshot 2020-02-15 at 14 27 19

I could really use some help!

@tastyqbit I also ran into the same issue on Safari and Internet Explorer. As you mentioned, scrolling past the expanded row and then scrolling back allows it render correctly, but of course that doesn't really solve the problem.

If you find any workarounds please let me know!

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

  • your list row height depends on only inner text (plus maybe some elements with determined dimensions)
  • and your list has fixed width

you can use CanvasRenderingContext2D.measureText() tо calculate row height instead of rendering whole component :poop:

CodeSandbox

@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/[email protected]
https://bundlephobia.com/[email protected]

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

  1. All items have style={position: absolute, left: 0, top: 0} which doesn't let me use this style since all options sit on top of each other.
  2. If I don't use the style prop, the list is shown well, but when I scroll a bit, the part of the list with options in it shrinks, while the total height remains unchanged. Thus, when I scroll, I get x pixels of actual options and length-x pixels white space.

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.

Was this page helpful?
0 / 5 - 0 ratings