I am using react virtualize table with many sub components in it and have very bad performance when rendering it.
it gets more aweful after scrolling, clicking buttons...
<TableContainer className={classes.table}>
<AutoSizer>
{({ height, width }) => (
<Table
height={height}
width={width}
rowHeight={64}
headerHeight={84}
rowCount={!isLoading ? tableRowsData.length : LOADING_ROWS_COUNT}
gridStyle={{
direction: 'inherit',
}}
rowGetter={({ index }) => getRowRow(index)}
className={classes.table}
rowClassName={getRowClassName}
noRowsRenderer={noRowsRendererHandler}
disableHeader={showEmptyState}
>
{Object.keys(headersConfig).map((key) => {
return (
<Column
key={key}
headerRenderer={({dataKey}) => headersConfig[dataKey].content}
cellRenderer={({ cellData }) => cellData}
dataKey={key}
width={headersConfig[key].width}
/>
)
})}
</Table>
)}
</AutoSizer>
</TableContainer>
the headerConfig is an object with all the column components.
how can I use this table wiser? how can I prevent many unnecessary re-renders?
am I need to use the rowRenderer prop? if so, can I get an example or a link to understand the implementation?
tnx
cheers
Related
I have an multigrid table in react virtualized and I cant change the style yo rtl .
I tried the props in document didn't work :(
I want my fixed columns to start from right
<AutoSizer>
{({ height, width }) => (
<MultiGrid
style={{ direction: "rtl" }}
cellRenderer={cellRenderer}
fixedColumnCount={2}
fixedRowCount={1}
height={500}
rowHeight={40}
rowCount={heightcount}
columnCount={headercolumns.length}
columnWidth={({ index }) => headercolumns[index].width}
width={width}
scrollToAlignment="end"
/>
)}
</AutoSizer>
I'm using react-infinite-scroll-component with Mantine's Select component, and have come across an issue. Basically whenever new data loads, the scroll bar resets all the way to the top, which as you can imagine is quite annoying in terms of UX.
Does anyone have a clue of why this is happening? While inspecting the DOM, it seems that the infinite scroll component completely re-renders for some reason.
You can see what I mean in this gif:
I'm almost sure that you are using some state for checking. I will give you a real bad example & solution for it.
Bad example which isn't works:
const hasData = !isLoading && postsResp?.content?.length;
{!hasData && (
<InfiniteScroll
dataLength={postsResp?.content?.length}
next={() => getContentFeed(true)}
hasMore={!postsResp?.last}
loader={(
<Skeleton
variant='text'
width={120}
height={24}
sx={{ margin: 'auto' }}
/>
)}
>
{postsResp?.content?.map((post: Content) => (
<Post key={`post_${post.uuid}+${Math.random()}`} post={post} />
))}
</InfiniteScroll>
) : (
'No posts'
)}
And this is a one which works good:
I know that you noticed i've moved the check if hasData on other place. I did that because each time this state is updating with new value and react re-render my component. That's why the scroll goes on top each time.
{(!hasData && !isLoading) && (
'No posts'
)}
<InfiniteScroll
dataLength={postsResp?.content?.length ?? 0}
next={() => getContentFeed(true)}
hasMore={!postsResp?.last}
loader={(
<Skeleton
variant='text'
width={120}
height={24}
sx={{ margin: 'auto' }}
/>
)}
>
{postsResp?.content?.map((post: Content) => (
<Post key={`post_${post.uuid}+${Math.random()}`} post={post} />
))}
</InfiniteScroll>
The main idea here is to remember to do not update any state according to your infinity scroll which can re-render your component.
I'm having trouble with react-virtualized Table (inside InfiniteLoader inside AutoSizer) with custom row renderer. Header row is rendered, but no data rows. Neither rowRenderer or rowGetter even get called for any row. I checked the data is there (this.props.requests).
What am I missing, or, how do I go about debugging?
<AutoSizer>
{({ height, width }) => (
<InfiniteLoader
isRowLoaded={this.isRowLoaded}
loadMoreRows={this.props.loadMoreEntries}
rowCount={(this.props.requests || []).length}
>
{({ onRowsRendered, registerChild }) => (
<Table
deferredMeasurementCache={this._cache}
onRowsRendered={onRowsRendered}
overscanRowCount={2}
ref={registerChild}
height={height}
headerHeight={50}
rowCount={(this.props.requests || []).length}
rowHeight={this._cache.rowHeight}
rowRenderer={this._rowRenderer}
rowGetter={this._rowGetter}
onRowClick={this.rowClicked}
width={width}
>
<Column
dataKey="requestType"
label="RqType"
width={100}
cellRenderer={this._renderRequestType}
/>
...
</Table>
)}
</InfiniteLoader>
)}
</AutoSizer>
My guess would be that the container div has no fixed height, and since you are using the Autosizer your table ends up with height = 0. Try with a fixed height in the props of Table and for the container div (maybe based on the current number of rows * row height).
You can also check that the rowCount is positive, but it should be ok as far as I can tell.
I am trying to combine a custom CSS table with the react virtualized window scroller. I currently can get the table to display, but am having trouble figuring out how to combine styling to that table, or add any logic to the table rows.
<WindowScroller>
{({ height, isScrolling, onChildScroll, scrollTop }) => (
<Table
autoHeight
width={1000}
height={700}
headerHeight={20}
rowHeight={30}
isScrolling={isScrolling}
onScroll={onChildScroll}
rowCount={table.length}
scrollTop={scrollTop}
rowGetter={({ index }) => table[index]}
>
<Column
label='Item1'
dataKey='item1'
width={150}
/>
<Column
width={200}
label='item2'
dataKey='item2'
/>
<Column
width={200}
label='item3'
dataKey='item3'
/>
<Column
width={150}
label='item4'
dataKey='item4'
/>
<Column
width={200}
label='item5'
dataKey='item5'
/>
</Table>
)}
</WindowScroller>
Definitely review the docs. You'll likely be passing both some type of style props and event props to the components - so you need to understand how those components define and accept those props. This is only possible by reviewing the documentation of the library.
EDIT:
Here are the propTypes for the <Table /> component:
https://github.com/bvaughn/react-virtualized/blob/master/docs/Table.md
You'll see that it accepts custom event handlers like onRowClick but also style props like rowStyle
I have a table that retrieves data from a json called approvalsData with fields name, type, and owners. Table pulls the data just fine. And the dialog opens. But I can't figure out how to pull that row data in the dialog. Not the entire json data, just the row I am clicking on.
What am I missing here? I'm guessing a lot :)
<TableBody>
{approvalsData.map( (row, index) => (
<TableRow
key={index}
onTouchTap={this.handleApprovalDialogOpen}>
<TableRowColumn>{row.name}</TableRowColumn>
<TableRowColumn>{row.type}</TableRowColumn>
<TableRowColumn>{row.owner}</TableRowColumn>
<Dialog
modal={false}
contentStyle={dialogStyle}
open={this.state.open}
onRequestClose={this.handleApprovalDialogClose}>
<Col key={index}>
<div>Name: <span>{this.name}</span></div>
<div>Type: <span>{this.type}</span></div>
<div>Owner: <span>{this.owner}</span></div>
</Col>
</Dialog>
</TableRow>
))}
</TableBody>
UPDATE
Inspecting the source, I realized that by including the Dialog inside the loop, I was displaying a dialog for every instance of the table rows. No wonder I was just seeing the last one. The others were behind it lol. ANyway, I moved it outside of the loop but now I can't reach the table row data from the table itself. I can reach the data by pointing to the json itself. The example below is showing the first index in the json, but that is not what I want. I want to show the row that I want to click on.
<TableBody>
{approvalsData.map( (row, index) => (
<TableRow
key={index}
onTouchTap={this.handleApprovalDialogOpen}>
<TableRowColumn>{row.name}</TableRowColumn>
<TableRowColumn>{row.type}</TableRowColumn>
<TableRowColumn>{row.owner}</TableRowColumn>
</TableRow>
))}
</TableBody>
<Dialog
modal={false}
contentStyle={dialogStyle}
open={this.state.open}
onRequestClose={this.handleApprovalDialogClose}>
<Col>
<div>Name: <span>{approvalsData[0].name}</span></div>
<div>Type: <span>{approvalsData[0].type}</span></div>
<div>Owner: <span>{approvalsData[0].owner}</span></div>
</Col>
</Dialog>
See the webpackbin
Thanks in advance
I am assuming that you set the open state in handleApprovalDialogOpen callback. You can bind the callback to the index (or id if any) of the row.
// some code
onTouchTap={this.handleApprovalDialogOpen.bind(this, index)}
<Dialog
modal={false}
contentStyle={dialogStyle}
open={this.state.open}
onRequestClose={this.handleApprovalDialogClose}>
<Col>
<div>Name: <span>{approvalsData[this.state.openRowIndex].name}</span></div>
<div>Type: <span>{approvalsData[this.state.openRowIndex].type}</span></div>
<div>Owner: <span>{approvalsData[this.state.openRowIndex].owner}</span></div>
</Col>
</Dialog>
handleApprovalDialogOpen(rowIndex, event) {
this.setState({open: true, openRowIndex: rowIndex})
}
#mukesh's approach looks solid. You're probably getting undefined because you're trying to access approvalsData with an index that does not exist. Try his solution and add:
<TableBody>
{approvalsData.map( (row, index) => (
<TableRow
key={index}
onTouchTap={(e) => this.handleApprovalDialogOpen(index, e)}>
<TableRowColumn>{row.name}</TableRowColumn>
<TableRowColumn>{row.type}</TableRowColumn>
<TableRowColumn>{row.owner}</TableRowColumn>
</TableRow>
))}
</TableBody>