<!DOCTYPE html>
<html>
  <head>
    <script src="https://unpkg.com/react/dist/react-with-addons.min.js"></script>
    <script src="https://unpkg.com/react-dom/dist/react-dom.min.js"></script>
    <script src="https://unpkg.com/react-virtualized/dist/umd/react-virtualized.js"></script>

    <link rel="stylesheet" href="https://unpkg.com/react-virtualized/styles.css">
    <link rel="stylesheet" href="styles.css">
  </head>

  <body>
    <div id="root"></div>
    <script src="script.js"></script>
  </body>

</html>
var InfiniteLoader = ReactVirtualized.InfiniteLoader;
var WindowScroller = ReactVirtualized.WindowScroller;
var AutoSizer = ReactVirtualized.AutoSizer;
var Table = ReactVirtualized.Table;
var Column = ReactVirtualized.Column;
var Component = React.Component;

function getServerData(search, fromIdx) {
  let data = [];
  if (search === 'banana') {
    // Server has absolutely no bananas :(
  } else if (search === 'carrots') {
    // Server has only 1 carrot
    for (let i = 0; i < 1; i++) {
      data.push({name: `carrots ${i}`});
    }
  } else if (search === 'tomatoes') {
    // Server has only 5 tomatoes
    for (let i = 0; i < 5; i++) {
      data.push({name: `tomatoes ${i}`});
    }
  } else if (search === 'birds') {
    // Server has exactly 200 birds
    if (fromIdx === 200)
      return data;
    for (let i = fromIdx; i < fromIdx+100; i++) {
      data.push({name: `${search} ${i}`});
    }
  } else {
    // Server has tones of potatoes or other stuff
    for (let i = fromIdx; i < fromIdx+100; i++) {
      data.push({name: `${search} ${i}`});
    }
  }
  return data;
}


class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      list: [],
      rowCount: 0,
      search: 'potatoes',
    };
  }
  
  loadMoreRows({ startIndex, stopIndex }) {
    console.log('LoadMoreRows', this.state.search);
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        const newDataFromServer = getServerData(this.state.search, this.state.list.length);
        const newList = this.state.list.concat(newDataFromServer);
        const hasNextPage = newDataFromServer.length === 100;
        const newCount = hasNextPage ? newList.length + 1 : newList.length;
        this.setState({
          rowCount: newCount,
          list: newList,
        }, () => {
          resolve();
        });
      }, 1000);
    });
  }

  isRowLoaded({ index }) {
    //console.log(`isRowLoaded (${index < this.state.list.length}) index: ${index}, listLength: ${this.state.list.length}`);
    return index < this.state.list.length;
  }

  rowGetter({index}) {
    if (!this.isRowLoaded({ index })) {
      return {name: 'loading...'};
    }
    return this.state.list[index];
  }
  
  // Empty the list and set row count to 1 to enable infinite scroll
  // I think we should reset memoizer here.
  resetList() {
    this.setState({list: [], rowCount: 1});
  }
  
  componentDidMount() {
    // When we first start, we want to call the server for data
    this.resetList();
  }
  
  searchChanged(evt) {
    this.setState({search: evt.target.value});
  }
  
  handleSearch(evt) {
    // We want to call the server again
    this.resetList();
  }

  render() {
    return (
      <div>
        <input type="text" value={this.state.search} onChange={this.searchChanged.bind(this)} />
        <button onClick={this.handleSearch.bind(this)}>Search</button>
        <InfiniteLoader isRowLoaded={this.isRowLoaded.bind(this)}
                        loadMoreRows={this.loadMoreRows.bind(this)}
                        rowCount={this.state.rowCount}
                        threshold={10}>
          {({ onRowsRendered, registerChild }) => (
            <WindowScroller>
            {({ height, isScrolling, scrollTop }) => (
              <AutoSizer disableHeight>
              {({ width }) => (
                <Table ref={registerChild}
                       autoHeight
                       height={height}
                       width={width}
                       headerHeight={27}
                       onRowsRendered={onRowsRendered}
                       rowCount={this.state.rowCount}
                       rowHeight={27}
                       scrollTop={scrollTop}
                       noRowsRenderer={() => <div style={{textAlign: 'center'}}>No rows</div>}
                       rowGetter={this.rowGetter.bind(this)}
                >
                  <Column
                    label='Name'
                    dataKey='name'
                    width={100}
                    maxWidth={400}
                  />
                </Table>
              )}
              </AutoSizer>
            )}
            </WindowScroller>
          )}
        </InfiniteLoader>
      </div>
    );
  }
}

ReactDOM.render(<App />, document.getElementById('root'));
.List {
  border: 1px solid black;
  box-sizing: border-box;
}
.Row {
  width: 100%;
  height: 100%;
  border-bottom: 1px solid black;
  display: flex;
  align-items: center;
  padding: 0 0.5rem;
  box-sizing: border-box;
}