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

getTotalSize when using itemSize array. #60

Open
jeroenransijn opened this issue Jul 31, 2018 · 2 comments
Open

getTotalSize when using itemSize array. #60

jeroenransijn opened this issue Jul 31, 2018 · 2 comments

Comments

@jeroenransijn
Copy link

jeroenransijn commented Jul 31, 2018

When I learned itemSize can be a getter or array — I was hoping the array approach would help with the getTotalSize function and reduce the total height of the container — instead of estimating it.

In of our use cases the heights for each row are much different, resulting in janky scrolling and poor estimates for the total height.

The below example is just me trying to explain what I mean. The actual implementation might be different, for example, it might make sense to determine this in the constructor and updateConfig — as well as have some caching.

/**
   * Total size of all items being measured.
   * This value will be completedly estimated initially.
   * As items as measured the estimate will be updated.
   * ---
   * When itemSizeGetter is an array, use it to determine the total height.
   */
  getTotalSize(): number {
    const lastMeasuredSizeAndPosition = this.getSizeAndPositionOfLastMeasuredItem();

    // Just an example.
    if (Array.isArray(this.itemSizeGetter)) {
      return this.itemSizeGetter.reduce((acc, currentValue) {
        return acc + currentValue
      }, 0)
    }

    return (
      lastMeasuredSizeAndPosition.offset +
      lastMeasuredSizeAndPosition.size +
      (this.itemCount - this.lastMeasuredIndex - 1) * this.estimatedItemSize
    );
  }

@clauderic do you have any thoughts around this? I wouldn't mind passing a property to accomplish this either. Potentially we can do the same if itemSizeGetter is a function.

Update

Looking at the code it seems that itemSizeGetter is always a function within the component:

  itemSizeGetter = (itemSize: Props['itemSize']) => {
    return index => this.getSize(index, itemSize);
  };

I am currently trying out adding a preCalculateTotalHeight bool prop in my fork.

@jeroenransijn
Copy link
Author

jeroenransijn commented Jul 31, 2018

Here is an example of what I am describing above

scrolling total size

const range = N => Array.from({length: N}, (_, k) => k + 1);

class MixedHeight extends React.Component<any, any> {
  constructor(props: any) {
    super(props);
    this.state = {
      items: range(1000).map(() => {
        return Math.max(Math.ceil(Math.random() * 1000), 50);
      }),
    };
  }

  renderItem = ({style, index}: {style: ItemStyle; index: number}) => {
    return (
      <div className="Row" style={style} key={index}>
        Row #{index}. Height: #{this.state.items[index]}
      </div>
    );
  };

  render() {
    return (
      <div className="Root">
        <VirtualList
          width="auto"
          height={400}
          itemCount={1000}
          renderItem={this.renderItem}
          itemSize={this.state.items}
          className="VirtualList"
        />
      </div>
    );
  }
}

@jeroenransijn
Copy link
Author

Got it to work, about to put in a PR. Scrolling is buttery smooth.

scrolling total size fixed

<VirtualList
  preCalculateTotalHeight
  width="auto"
  height={400}
  itemCount={1000}
  renderItem={this.renderItem}
  itemSize={this.state.items}
  className="VirtualList"
/>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant