I've just finished a working table with using InfiniteLoader, Table, Column, and AutoSizer, and I realize this table does not scale horizontally with the browser window. It took me a long time to get this working despite much of the library being well documented. What I want to achieve is a HTML like table that resizes based on the browser window's width, grows row heights vertically as content wraps, and uses infinite load with varying row heights. Are all of these points possible with react-virtualized? It seems best to ask first as combining all the moving parts of this library can be tricky. Thanks!
Here is my component:
import React from 'react';
import fetch from 'isomorphic-fetch';
import { InfiniteLoader, Table, Column, AutoSizer } from 'react-virtualized';
import { connect } from 'react-redux';
import { CSSTransitionGroup } from 'react-transition-group';
import { fetchProspects } from '../actions/prospects';
import Footer from './footer';
class ProspectsTable extends React.Component {
constructor(props, context) {
super(props, context);
this.renderProspects = this.renderProspects.bind(this);
this.isRowLoaded = this.isRowLoaded.bind(this);
this.loadMoreRows = this.loadMoreRows.bind(this);
this.rowRenderer = this.rowRenderer.bind(this);
this.state = {
remoteRowCount: 200,
list: [
{
fullName: '1 Vaughn',
email: '[email protected]',
phone: '608 774 6464',
programOfInterest: 'Computer Science',
status: 'Active',
dateCreated: '10/31/2017',
},
{
fullName: '2 Vaughn',
email: '[email protected]',
phone: '608 774 6464',
programOfInterest: 'Computer Science',
status: 'Active',
dateCreated: '10/31/2017',
},
{
fullName: '3 Vaughn',
email: '[email protected]',
phone: '608 774 6464',
programOfInterest: 'Computer Science',
status: 'Active',
dateCreated: '10/31/2017',
},
],
};
}
isRowLoaded({ index }) {
return !!this.state.list[index];
}
loadMoreRows({ startIndex, stopIndex }) {
return fetch(`http://localhost:5001/api/prospects?startIndex=${startIndex}&stopIndex=${stopIndex}`)
.then((response) => {
console.log('hi', response);
console.log('hi', this.props);
});
}
rowRenderer({ key, index, style }) {
return (
<div
key={key}
style={style}
>
{this.state.list[index]}
</div>
);
}
render() {
return (
<InfiniteLoader
isRowLoaded={this.isRowLoaded}
loadMoreRows={this.loadMoreRows}
rowCount={this.state.remoteRowCount}
>
{({ onRowsRendered, registerChild }) => (
<div>
<AutoSizer>
{({ width }) => (
<Table
ref={registerChild}
onRowsRendered={onRowsRendered}
width={width}
height={300}
headerHeight={20}
rowHeight={30}
rowCount={this.state.list.length}
rowGetter={({ index }) => this.state.list[index]}
>
<Column
label="Full Name"
dataKey="fullName"
width={width / 6}
/>
<Column
width={width / 6}
label="Email"
dataKey="email"
/>
<Column
width={width / 6}
label="Phone"
dataKey="phone"
/>
<Column
width={width / 6}
label="Program of Interest"
dataKey="programOfInterest"
/>
<Column
width={width / 6}
label="Status"
dataKey="status"
/>
<Column
width={width / 6}
label="Date Created"
dataKey="dateCreated"
/>
</Table>
)}
</AutoSizer>
</div>
)}
</InfiniteLoader>
);
}
}
}
const mapStateToProps = state => ({
prospects: state.prospects,
});
export default connect(mapStateToProps)(ProspectsTable);
Here is a plnkr that closely resembles my code, I referenced this a lot: https://plnkr.co/edit/lwiMkw?p=preview
Great work so far on an ambitious project. A couple thoughts on achieving your remaining objectives:
Resizes based on the browser window's width
Try Putting your AutoSizer
component at the top level of this hierarchy, and ensure its parent component's width changes with the viewport. This could be achieved as simply as a parent div
with width: 100vw
.
grows row heights vertically as content wraps, and uses infinite load with varying row heights
These can both be achieved by dynamically setting your row heights based on data. From the docs on the rowHeight
prop for Table
:
Either a fixed row height (number) or a function that returns the height of a row given its index: ({ index: number }): number
React-Virtualized does its magic by calculating its dimensions ahead of time, so you're not going to be able to get flex-wrap
functionality or other CSS-based solutions to work correctly. Instead, determine how you can use the data for a given row (and potentially the current screen dimensions) to calculate what the height should be for that row. For example:
const BASE_ROW_HEIGHT = 30;
const MAX_NAME_CHARS_PER_LINE = 20;
...
getRowHeight = ({ index }) => {
const data = this.state.list[index];
// Not a great example, but you get the idea;
// use some facet of the data to tell you how
// the height should be manipulated
const numLines = Math.ceil(fullName.length / MAX_NAME_CHARS_PER_LINE);
return numLines * BASE_ROW_HEIGHT;
};
render() {
...
<Table
...
rowHeight={this.getRowHeight}
>
}
For additional reference, I found the source code for the React-Virtualized Table
example quite informative - especially the lines regarding dynamically setting row height:
_getRowHeight({ index }) {
const { list } = this.context;
return this._getDatum(list, index).size;
}
Best of luck!