I am using React-table for one of my projects. I implemented the row selection as mentioned in the docs.
below is my table.js
import React, { useEffect, useMemo } from 'react'
import { useTable, usePagination, useRowSelect } from 'react-table';
import {Button, Dropdown, DropdownButton, Form} from 'react-bootstrap';
import BTable from 'react-bootstrap/Table';
export function Table({ columns, data, fetchData, noDataMessage, pageCount: controlledPageCount, loading, rowSelectionEnabled, getSelectedRows }) {
const memoizedColumns = useMemo(() => columns, [columns]);
const memoizedData = useMemo(() => data, [data]);
// Use the state and functions returned from useTable to build your UI
const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
prepareRow,
page,
canPreviousPage,
canNextPage,
pageOptions,
pageCount,
gotoPage,
nextPage,
previousPage,
setPageSize,
selectedFlatRows,
isAllRowsSelected,
state: { pageIndex, pageSize, selectedRowIds },
} = useTable({
columns: memoizedColumns,
data: memoizedData,
noDataMessage,
initialState: { pageIndex: 0, pageSize: 15 },
manualPagination: true,
pageCount: controlledPageCount,
},usePagination, useRowSelect,
hooks => {
rowSelectionEnabled && hooks.visibleColumns.push(columns => [
// Let's make a column for selection
{
id: 'selection',
// The header can use the table's getToggleAllRowsSelectedProps method
// to render a checkbox
Header: ({ getToggleAllRowsSelectedProps }) => (
<div>
<IndeterminateCheckbox {...getToggleAllRowsSelectedProps()} />
</div>
),
// The cell can use the individual row's getToggleRowSelectedProps method
// to the render a checkbox
Cell: ({ row }) => (
<div>
<IndeterminateCheckbox {...row.getToggleRowSelectedProps()} />
</div>
),
},
...columns,
])
}
)
const setSize = (selectedVal) => {
setPageSize(selectedVal);
}
// const fetchDataDebounced = useAsyncDebounce(fetchData, 100);
React.useEffect(() => {
data.length > 0 && fetchData && fetchData({ pageIndex, pageSize })
}, [fetchData, pageIndex, pageSize])
// React.useEffect(() => {
// data.length === 0 && gotoPage(0)
// }, [data])
// Render the UI for your table
return (
<>
<BTable striped bordered loading={true} minRows={0} className='border-radius-important' {...getTableProps()}>
<thead>
{headerGroups.map(headerGroup => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map(column => (
<th {...column.getHeaderProps()}>{column.render('Header')}</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{page.length > 0 ? (page.map((row, i) => {
prepareRow(row)
return (
<tr {...row.getRowProps()}>
{row.cells.map(cell => {
return <td {...cell.getCellProps()}>{cell.render('Cell')}</td>
})}
</tr>
)
})) : <tr style={{height: '350px'}}><td colSpan={10} style={{verticalAlign: 'middle'}}><NoDataComponent message={noDataMessage}/></td></tr>}
</tbody>
</BTable>
{ pageCount > 1 ? (<div className="pagination">
<div style={{width: '100%', paddingTop: '15px'}}>
<div style={{display: 'flex', float: 'right'}}>
<div style={{display: 'block'}}>
<div>
<Button variant='outline-primary' onClick={() => gotoPage(0)} disabled={!canPreviousPage}>
{'<<'}
</Button>{' '}
<Button variant='outline-primary' onClick={() => previousPage()} disabled={!canPreviousPage}>
{'<'}
</Button>{' '}
<Button variant='outline-primary' onClick={() => nextPage()} disabled={!canNextPage}>
{'>'}
</Button>{' '}
<Button variant='outline-primary' onClick={() => gotoPage(pageCount - 1)} disabled={!canNextPage}>
{'>>'}
</Button>{' '}
</div>
<div>
Page{' '}
<strong>
{pageIndex + 1} of {pageOptions.length}
</strong>{' '}
</div>
</div>
{/* <div>
| Go to page:{' '}
<input
type="number"
defaultValue={pageIndex + 1}
onChange={e => {
const page = e.target.value ? Number(e.target.value) - 1 : 0
gotoPage(page)
}}
style={{ width: '100px' }}
/>
</div>{' '} */}
</div>
<DropdownButton
style={{float: 'left'}}
title={pageSize}
onSelect={setSize}
>
{[10, 20, 30, 40, 50].map(pageSize => (
<Dropdown.Item eventKey={pageSize}>
{pageSize}
</Dropdown.Item>
))}
</DropdownButton>
</div>
</div>) : null }
{getSelectedRows && getSelectedRows(selectedRowIds, selectedFlatRows, isAllRowsSelected)}
</>
)
}
const NoDataComponent = props => (
// <NoData noDataTitle="This is the dynamic title" {...props} />
<div style={{width: '100%', height: '100%', textAlign: 'center', fontWeight: '700', fontSize: 'large'}}>{props.message}</div>
);
const IndeterminateCheckbox = React.forwardRef(
({ indeterminate, ...rest }, ref) => {
const defaultRef = React.useRef()
const resolvedRef = ref || defaultRef
React.useEffect(() => {
resolvedRef.current.indeterminate = indeterminate
}, [resolvedRef, indeterminate])
return (
<>
<Form.Check type="checkbox" ref={resolvedRef} {...rest} />
</>
)
}
)
and the following is the code where i am using this table
getSelectedRows = (rowIds, rowData, isAllRowsSelected) => {
this.setState({selectedData: rowData});
}
<Table columns={this.state.columns} data={this.state.data} rowSelectionEnabled={true} noDataMessage='There is no data to display' getSelectedRows={this.getSelectedRows} fetchData={this.fetchData} pageCount={this.state.count}></Table>
So whenever the checkbox is selected, following line gets triggered in table.js:
{getSelectedRows && getSelectedRows(selectedRowIds, selectedFlatRows, isAllRowsSelected)}
and getSelectedRows function gets called in my component.
But after that page crashes with the error: Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate
I read somewhere that memoizing data and columns will fix the issue as it is going into loop rendering again and again. So I memoized data and columns at the start of table.js file. But still the issue is there.
Can someone please help on this. Thanks in advance!