title: react-virtualized WindowScroller performance issues
body: <p>I am using the react-virtualized library to create efficient news feed. The library is awesome. I combined WindowScroller, AutoSizer and VirtualScroll components to have inifinite scrolling behavior. The problem is that when I set the VirtualScroll height manually and don't use WindowScroller the performance is great in all browsers. However when I add the WindowScroller component, performance reduces significantly, especially in Firefox (v47.0). How can I optimize this so that it is feasible to use window scrolling?</p>
  
  <p>This is the News component, where the react-virtualized is used,
  I have 2 types of list items - header item and simple item, header item contains a date of a group of news, thus it is a little bit longer.</p>
  
  <pre class="lang-js prettyprint-override"><code>import React, { PropTypes, Component } from 'react';
  import Divider from 'material-ui/Divider';
  import Subheader from 'material-ui/Subheader';
  import { Grid, Row, Col } from 'react-flexbox-grid';
  import NewsItem from '../NewsItem';
  import styles from './styles.css';
  import CircularProgress from 'material-ui/CircularProgress';
  import Paper from 'material-ui/Paper';
  import classNames from 'classnames';
  import { InfiniteLoader, WindowScroller, AutoSizer, VirtualScroll } from 'react-virtualized';
  import shallowCompare from 'react-addons-shallow-compare';
  
  class News extends Component {
  
    componentDidMount() {
      this.props.onFetchPage(0);
    }
  
    shouldComponentUpdate(nextProps, nextState) {
      return shallowCompare(this, nextProps, nextState);
    }
  
    getRowHeight({ index }) {
      const elementHeight = 200;
      const headerHeight = 78;
      if (!this.isRowLoaded(index)) {
        return elementHeight;
      }
      return this.props.articles[index].isHeader ?
        headerHeight + elementHeight : elementHeight;
    }
  
    displayElement(article, isScrolling) {
      return (
        &lt;Paper
          key={article.id}
          className={classNames(styles.newsItemContainer, {
            [styles.scrolling]: isScrolling
          })}
        &gt;
          &lt;NewsItem {...article} /&gt;
          &lt;Divider /&gt;
        &lt;/Paper&gt;
      );
    }
  
    isRowLoaded(index) {
      return !this.props.hasNextPage || index &lt; this.props.articles.length;
    }
  
    renderRow(index, isScrolling) {
      if (!this.isRowLoaded(index)) {
        return (
          &lt;div className={styles.spinnerContainer}&gt;
            {this.props.isFetching ? &lt;CircularProgress /&gt; : null}
          &lt;/div&gt;
        );
      }
      const { isHeader, date, article } = this.props.articles[index];
      if (isHeader) {
        return (
          &lt;div&gt;
            &lt;Subheader
              key={date}
              className={styles.groupHeader}
            &gt;
              {date}
            &lt;/Subheader&gt;
            {this.displayElement(article, isScrolling)}
          &lt;/div&gt;
        );
      }
      return this.displayElement(article, isScrolling);
    }
  
    noRowsRenderer() {
      return (&lt;p&gt;No articles found&lt;/p&gt;);
    }
  
    render() {
      const {
        articles,
        onFetchPage,
        pageNumber,
        isFetching,
        hasNextPage
      } = this.props;
  
      const loadMoreRows = isFetching ?
        () =&gt; {} :
        () =&gt; onFetchPage(pageNumber + 1);
  
      const rowCount = hasNextPage ? articles.length + 1 : articles.length;
  
      return (
        &lt;Grid&gt;
          &lt;Row&gt;
            &lt;Col xs={12} sm={8} smOffset={2}&gt;
              &lt;InfiniteLoader
                isRowLoaded={({ index }) =&gt; this.isRowLoaded(index)}
                loadMoreRows={loadMoreRows}
                rowCount={rowCount}
              &gt;
                {({ onRowsRendered, registerChild, isScrolling }) =&gt; (
                  &lt;WindowScroller&gt;
                    {({ height, scrollTop }) =&gt; (
                      &lt;AutoSizer disableHeight&gt;
                        {({ width }) =&gt; (
                          &lt;VirtualScroll
                            autoHeight
                            ref={registerChild}
                            height={height}
                            rowCount={rowCount}
                            rowHeight={(...args) =&gt; this.getRowHeight(...args)}
                            rowRenderer={({ index }) =&gt; this.renderRow(index, isScrolling)}
                            width={width}
                            noRowsRenderer={this.noRowsRenderer}
                            onRowsRendered={onRowsRendered}
                            overscanRowCount={10}
                            scrollTop={scrollTop}
                          /&gt;
                        )}
                      &lt;/AutoSizer&gt;
                    )}
                  &lt;/WindowScroller&gt;
                )}
              &lt;/InfiniteLoader&gt;
            &lt;/Col&gt;
          &lt;/Row&gt;
        &lt;/Grid&gt;
      );
    }
  }
  
  News.propTypes = {
    articles: PropTypes.array.isRequired,
    onFetchPage: PropTypes.func.isRequired,
    isFetching: PropTypes.bool.isRequired,
    pageNumber: PropTypes.number.isRequired,
    hasNextPage: PropTypes.bool.isRequired
  };
  
  export default News;
  </code></pre>
  
  <p>And the list item is the following component:</p>
  
  <pre class="lang-js prettyprint-override"><code>import React, { PropTypes } from 'react';
  import styles from './styles.css';
  import { Row, Col } from 'react-flexbox-grid';
  import shallowCompare from 'react-addons-shallow-compare';
  import pick from 'lodash/pick';
  import NewsItemContent from '../NewsItemContent';
  
  class NewsItem extends React.Component {
  
    shouldComponentUpdate(nextProps, nextState) {
      return shallowCompare(this, nextProps, nextState);
    }
  
    render() {
      const contentProps = pick(this.props, [
        'title', 'description', 'seedUrl', 'seedCode', 'date'
      ]);
      return (
        &lt;div
          onClick={() =&gt; window.open(this.props.url, '_blank')}
          className={styles.newsItem}
        &gt;
          {this.props.imageUrl ?
            &lt;Row&gt;
              &lt;Col xs={3}&gt;
                &lt;div
                  role="presentation"
                  style={{ backgroundImage: `url(${this.props.imageUrl})` }}
                  className={styles.previewImage}
                /&gt;
              &lt;/Col&gt;
              &lt;Col xs={9}&gt;
                &lt;NewsItemContent {...contentProps} /&gt;
              &lt;/Col&gt;
            &lt;/Row&gt; :
            &lt;Row&gt;
              &lt;Col xs={12}&gt;
                &lt;NewsItemContent {...contentProps} /&gt;
              &lt;/Col&gt;
            &lt;/Row&gt;
          }
        &lt;/div&gt;
      );
    }
  }
  
  NewsItem.propTypes = {
    imageUrl: PropTypes.string,
    description: PropTypes.string.isRequired,
    title: PropTypes.string.isRequired,
    url: PropTypes.string.isRequired,
    date: PropTypes.object.isRequired,
    seedUrl: PropTypes.string.isRequired,
    seedCode: PropTypes.string.isRequired
  };
  
  export default NewsItem;
  </code></pre>
  
  <p>NewsItemContent here is a simple pure component without any logic, so I won't put it here.</p>
  
  <p>Thank you!</p>
  
  <p>Update:
  I've recorded performance timelines in firefox both in case of window scrolling and block scrolling:</p>
  
  <ul>
  <li><a href="https://www.dropbox.com/s/19fctwllgwvxgct/blocked.json?dl=0" rel="noreferrer">Block scrolling</a></li>
  <li><a href="https://www.dropbox.com/s/p66xe22miu884dk/windowed.json?dl=0" rel="noreferrer">Window scrolling</a></li>
  </ul>