React Virtualized table with CellMeasurer is not calculating the height properly - javascript

I have a strange issue going on. The react-virtualized table with CellMeasurer is not calculating the height properly.
My render function looks something like this :-
<Table
deferredMeasurementCache={this._cache}
className={mainClasses}
width={500}
height={500}
headerHeight={headerHeight}
rowHeight={this._cache.rowHeight}
rowCount={dataList.length}
sort={this.sort}
sortBy={sortBy}
sortDirection={sortDirection}
rowGetter={({ index }) => dataList[index]}
rowRenderer={this.rowRenderer}
overscanRowCount={overscanRowCount}
onRowClick={onRowClick}
>
{
columnsDef.map((item, index) => {
if (index === 0) {
return (
<Column
key={item.dataKey}
dataKey={item.dataKey}
width={25}
cellRenderer={this.checkboxCellRenderer}
disableSort={!this.isSortEnabled(item)}
headerRenderer={this.checkBoxHeaderRenderer}
/>
);
}
return (
<Column
key={item.dataKey}
dataKey={item.dataKey}
width={item.width ? item.width : 0}
label={item.label}
cellRenderer={this.dynamicCellRenderer}
disableSort={!this.isSortEnabled(item)}
headerRenderer={this.headerRenderer}
flexGrow={item.flexGrow}
/>
);
})
}
</Table>
My dynamic cell renderer function is as follows :-
dynamicCellRenderer = (data) => {
return (
<CellMeasurer
cache={this._cache}
columnIndex={0}
key={data.cellData}
parent={data.parent}
rowIndex={data.rowIndex}
>
<div
style={{
whiteSpace: 'normal'
}}
>
{data.cellData}
</div>
</CellMeasurer>
);
}
I have cache defined in constructor :-
constructor(props) {
super(props);
this._cache = new CellMeasurerCache({ minHeight: props.rowHeight, fixedWidth: true });
}
Can anyone please help me with where am I going wrong. Am I missing something with implementation of CellMeasurer? Any help is appreciated. Thanks in advance.

I had the same issue.
I think that the problem is because each cell's height is calculated before it's content is loaded.
I used the parameter measure of the CellMeasurer and call it when the content is loaded
<CellMeasurer
cache={cache}
columnIndex={0}
key={key}
parent={parent}
rowIndex={index}
width={width}
>
{({measure}) => (
<Content onLoad={measure} />
)}
</CellMeasurer>

Related

How to make two rows inside one row react-virtualized?

I need to make for some rows react-virtualized from table, create 2 rows, 1 row it is row react-virtualized second row it is my custom row
Ho to do it, maybe has some example?
I tried use defaultTableRowRenderer() function,as far as I understand, this embeds newlines in react-virtualized table, but I not need this
its must look like this
table
My code look like this
return (
<>
<div style={{ height: "90vh" }}>
<AutoSizer>
{({ width, height }) => (
<TableVirtualized
headerHeight={70}
height={height}
overscanRowCount={5}
rowHeight={ 80}
rowCount={rowItems.length}
rowGetter={({index}) => rowItems[index]}
width={width}
className={className}
rowRenderer={rowRenderer}
>
{headerTitles.map((v:any, i:any)=>{
const key = Object.keys(v);
return (
<Column
label={v[`${key}`]}
dataKey={key}
width={200}
cellRenderer={(v: any)=> cell(v)}
key={i}
headerRenderer={()=> formatHeader(v[`${key}`])}
/>
)
}
)}
</TableVirtualized>
)}
</AutoSizer>
this my rowRender function. I think this is a bad way, because row react-virtualized height is fixed
const rowRenderer = (props: any) => {
const { index, style, className, key, rowData } = props;
if(rowData.attributes){
return (
<div className={cellProps.attributes.className}>
{defaultTableRowRenderer(props)}
<div className='blabla'>1</div>
</div>
)
}
return defaultTableRowRenderer(props);
}

How to measure cell size in react virtualized table

I'm trying to do autosized cell in react-virtualized Table.
Here is the table:
<AutoSizer>
{({ height, width }) => (
<Table
width={width}
height={height}
headerHeight={20}
rowHeight={30}
deferredMeasurementCache={cache.current}
rowCount={usersData.length}
rowGetter={({ index }) => usersData[index]}
cellRenderer={cellRenderer}
>
<Column label="User Data" dataKey="userData" width={width / 2} />
<Column label="Activities" dataKey="userActivity" width={width / 2} />
</Table>
)}
</AutoSizer>
Here is cellRenderer:
function cellRenderer(props) {
console.log(props);
return (
<CellMeasurer cache={cache} columnIndex={props.columnIndex} parent={props.parent} rowIndex={props.rowIndex}>
<div>{props.cellData}</div>
</CellMeasurer>
);
}
And as I saw guide for List I thought cellRenderrer should be in Table component, but it does nothing.
If i put cellRenderrer in column component it doesn't have key and style props to work correctly.
What am I supposed to do?
I solved my problem from example: https://github.com/bvaughn/react-virtualized/blob/e360d958b99fa965fd3f1caed4506403ad652cd3/source/CellMeasurer/CellMeasurer.DynamicHeightTableColumn.example.js

React Virtualized Auto Scroll Issue

I am using react-virtualized v-9.21.2 to display a list, I am having an issue on insertion of a new item, upon inserting a new item to the list I am clearing the cache and updating the listkey to auto resize the height, otherwise, the new added item will be cropped but when the listkey get updated the list automatically scroll to top and this is not a desired behavior, my code is as follow:
UNSAFE_componentWillReceiveProps(nextprops) {
if (this.props.items.length !== nexprops.items.lenght)) {
// clear the cache and update the listKey
this.cache.clearAll();
this.virtualizedList && this.virtualizedList.recomputeRowHeights();
this.listKey += 1
}
renderItem = ({ index, key, parent, style }) => {
return (
<CellMeasurer
cache={this.cache}
columnIndex={0}
key={`CellMeasurerRow_${key}`}
parent={parent}
rowIndex={index} >
<div
key={`Item__${key}`}
style={style}
className='row'>
<Item
style={style}
key={`Item_${index}`}
/>
</div>
</CellMeasurer>
)
}
render(){
return (
<WindowScroller
key={`Scroller_${this.listKey}`}
ref={(e) => this.windowRef = e} >
{({ height, isScrolling, onChildScroll, registerChild, scrollTop, }) => (
<AutoSizer>
{({ width }) => (
<React.Fragment key={registerChild}>
<List
ref={`ListKey_${this.listKey}`}
autoHeight
isScrolling={isScrolling}
onScroll={onChildScroll}
key={this.listKey}
scrollTop={scrollTop}
height={height}
rowCount={this.props.items.length}
rowRenderer={this.renderItem}
deferredMeasurementCache={this.cache}
rowHeight={this.cache.rowHeight}
width={width}
overscanRowCount={10} />
</React.Fragment>
)}
</AutoSizer>
)}
</WindowScroller>
)
}
I tried programmatically to scroll to adjust the height without the update of the key, it worked but still not accurate, So, How can I update the virtualized with a new item and adjust the height without scrolling ??
If your data has a unique key, I think you can create a ListItem component add an useEffect hook calling the measure function when the data change. This may have performance impact.
function ListItem(props) {
useEffect(props.measure, [props.data.id]);
return (
<div style={props.style}>
{/* content render */}
</div>
);
}
renderItem = ({ index, key, parent, style }) => {
const item = getItem(index); // suppose item data structure: { id: unique_key }
return (
<CellMeasurer
cache={this.cache}
columnIndex={0}
key={`CellMeasurerRow_${key}`}
parent={parent}
rowIndex={index}
>
{(measure) => (
<ListItem
key={`Item__${key}`} style={style}
data={item}
measure={measure}
/>
)}
</CellMeasurer>
)
}

Update list when redux store changes

I am trying to update the list when my redux store changes but for some odd reason it isn't. I have to manually refresh the page to see my changes. Here's the snippet of my List component and rowRenderer.
<InfiniteLoader
isRowLoaded={this._isRowLoaded}
loadMoreRows={this._loadMoreRows}
rowCount={visibleRequest.length}
>
{({ onRowsRendered, registerChild }) => (
<AutoSizer>
{({ height, width }) => (
<List
ref={registerChild}
className="List"
height={height}
rowHeight={listRowHeight}
onRowsRendered={onRowsRendered}
rowCount={rowCount}
rowRenderer={this._rowRenderer}
width={width}
/>
)}
</AutoSizer>
)}
</InfiniteLoader>
_rowRenderer = ({ index, key, style }) => {
const { loadedRowsMap, selected } = this.state;
const row = this.getDatum(index);
let content;
if (loadedRowsMap[index] === STATUS_LOADED) {
content = row;
} else {
content = (
<div className="placeholder" style={{ width: _.random(100, 200) }} />
);
}
return (
<PendingChat
key={key}
content={content}
style={style}
row={row}
{...this.props}
/>
);
};
Yeah, I ran into the same problem. Its because the references to your objects don't change when you do
const row = this.getDatum(index);
let content;
if (loadedRowsMap[index] === STATUS_LOADED) {
content = row;
}
Take a look at immutability.

Ternary operator on autoHeight for VirtualizedTable

I am stuck on how to make a Virtualized Table using the Autosizer to shrink to the smallest possible height until a certain maximum threshold.
Is there a way to convert my autoHeight to use a conditional value?
autoheight={height<500}
Here is my render function:
render(): ?React$Element<any> {
const { columns, selectedItems, rulesList } = this.state;
const { shouldRender, currentRule, sort } = this.props;
if (!shouldRender) return <div />;
return (
<Grid columns={1} id="rulesTabContent">
<Grid.Row style={NO_PADDING_BOTTOM}>
<Grid.Column>
<VirtualizedTable
id="rulesTable"
autoHeight={true}
height={500}
rowDef={rowDef => this.rowDef(rowDef, currentRule.id)}
onRowDoubleClick={this.checkExpanded}
columns={columns}
sortVals={sort}
setSort={this.updateSort}
sortFn={this.sortFunc}
getRowHeight={rowHeight}
noRowsRenderer={this.noRowsRenderer}
rowCount={rulesList.length}
setSelectedItems={this.setSelectedItems}
selectedItems={selectedItems}
list={rulesList}
/>
</Grid.Column>
</Grid.Row>
</Grid>
);
}
Here is the render function of VirtualizedTable, which is used above:
import {
AutoSizer,
Table,
Column,
SortIndicator,
SortDirection
} from "react-virtualized";
.
.
.
render() {
const {
list,
sortVals,
onRowClick,
onRowsRendered,
noRowsRenderer,
getRowHeight,
columns,
onRefresh,
...restOfProps
} = this.props;
return (
<AutoSizer disableHeight>
{({ width }) => (
<Table
headerClassName="virtualized-header"
headerHeight={HEADER_HEIGHT}
rowHeight={getRowHeight ? this._rowHeight : DEFAULT_ROW_HEIGHT}
overscanRowCount={OVERSCAN}
width={width}
sort={this._sort}
sortBy={sortVals.by}
sortDirection={sortVals.direction}
rowCount={list.size}
noRowsRenderer={this._noRows}
rowGetter={this._getRow}
rowClassName={this._getRowClassName}
rowRenderer={this._renderRow}
onRowsRendered={this._onRowsRendered}
onRowClick={this._onRowClick}
{...restOfProps}
>
{Array.isArray(columns)
? columns
: Object.keys(columns).map(key => columns[key])}
</Table>
)}
</AutoSizer>
);
}
}
It's hard to debug without a demo, but maybe something like this?
return (
<AutoSizer>
{({ width, height }) => (
<Table
height={height}
...
-
<VirtualizedTable
id="rulesTable"
autoHeight={height < 500}
height={Math.min(height, 500)}
A little more info, are you looking for this?
style={{height: 'auto', max-height: '500px', overflow: 'scroll'})
this.state = {
autoHeight: {overflowX: 'hidden'},
}
{rulesList.length < 50 ? this.setState({autoHeight: {overFlowX: 'hidden'}}) : this.setState({autoHeight: overFlowX: 'scroll'}) }
From the Devs...
style={{
overflowX: 'hidden',
overflowY: 'hidden'
}}
So you would need to add a style that looks something like this.
style={this.state.autoHeight}
Heres a closed issue on the topic
https://github.com/bvaughn/react-virtualized/issues/488

Categories