Reputation: 2354
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
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