XeniaSis
XeniaSis

Reputation: 2354

loadMoreRows not called on load

I have the following example implementing the InfiniteLoader with a Table. The problem is that loadMoreRows is not called on load or when the component is mounted. However, if I manually execute the API call and pass the result through props, loadMoreRows is called with startIndex 0 and thus I have the same API call twice.

import React = require('react');
import _ = require('lodash');
import Immutable = require('immutable');
import Api = require('./Api');

const STATUS_LOADING = 1,
      STATUS_LOADED = 2,
      LOG_LIMIT = 200;

interface Props {
    logEntries: Immutable.List<Immutable.Map<string, any>>;
}

interface State {
    logEntries?: Immutable.List<Immutable.Map<string, any>>;
    count?: number;
    loadedRowsMap?: any;
}

class LogViewer extends React.Component<Props, State> {
    constructor(props: Props) {
        super(props);

        this.state = {
            logEntries: props.logEntries,
            count: 0,
            loadedRowsMap: {}
        };
    }

    render() {
        return {this.renderLoader()};
    }

    private renderLoader() {
        const {logEntries, count} = this.state;
        return (
            <InfiniteLoader isRowLoaded={this.isRowLoaded.bind(this)}
                            loadMoreRows={this.loadMoreRows.bind(this)}
                            minimumBatchSize={LOG_LIMIT}
                            rowCount={logEntries.size} >
                {
                    ({onRowsRendered, registerChild}) => (
                        <AutoSizer disableHeight>
                            {
                                ({width}) => (
                                    <Table headerHeight={20}
                                           height={400}
                                           onRowsRendered={onRowsRendered}
                                           ref={registerChild}
                                           rowCount={count}
                                           className='log-entries'
                                           gridClassName='grid'
                                           headerStyle={{ fontSize: 15 }}
                                           rowGetter={({index}) => logEntries.get(index)}
                                           rowHeight={50}
                                           width={width} >
                                        <Column label='Name'
                                                key='name'
                                                dataKey='name'
                                                width={200} />
                                    </Table>
                                )
                            }
                        </AutoSizer>
                    )
                }
            </InfiniteLoader>
        );
    }

    private isRowLoaded({index}) {
        const {loadedRowsMap} = this.state;
        return !!loadedRowsMap[index];
    }

    private loadMoreRows({startIndex, stopIndex}) {
        const {loadedRowsMap, level, logEntries} = this.state;

        _.range(startIndex, stopIndex).forEach(i => {
            loadedRowsMap[i] = STATUS_LOADING;
        });
        this.setState({ loadedRowsMap });

        const offset = Math.floor((startIndex + 1) / LOG_LIMIT);
        return Api.logs(LOG_LIMIT, offset)
            .then(({body: [count, logs]}) => {
                _.range(startIndex, stopIndex).forEach(i => {
                    loadedRowsMap[i] = STATUS_LOADED;
                });
                const newLogs = logEntries.toJS().concat(logs);
                this.setState({
                    count,
                    logEntries: Immutable.fromJS(newLogs),
                    loadedRowsMap
                });
            });
    }
};

Upvotes: 2

Views: 3624

Answers (1)

bvaughn
bvaughn

Reputation: 13487

The problem is that loadMoreRows is not called on load or when the component is mounted.

Any time a range of rows loads, InfiniteLoader calls isRowLoaded for each row to determine if it needs to be loaded. If isRowLoaded returns false, then that row is queued up and loadMoreRows is called in chunks for each range of unloaded rows.

In your case above, I believe what's happening is that you're not passing any initial rows to the Table- so Grid is not rendering anything initially (because it has no rows to render) and so the rows-loaded caller I linked above has nothing to iterate over and nothing to load. You have a couple of options here- either kick off the first load yourself, or add a +1 empty row to tip InfiniteLoader off that it should request more data (like I do in this example).

Upvotes: 3

Related Questions