Problems with react-table using "useSortBy" - reactjs

I am having some problems on react-table using useSortBy. With no useSortBy the table works fine.
Getting this error:
Error: Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.
var COLUMNS = [
{
Header: 'Data Criação',
accessor: 'createdAt',
Cell: ({value})=> {return value ? format(new Date(value), 'dd/MM/yyyy') : ''},
},
{
Header: 'Nome',
accessor: 'name'
},
{
Header: 'Telefone',
accessor: 'mobile'
},
{
Header: 'Email',
accessor: 'email'
},
{
Header: 'Action',
accessor: (hit)=>{
return <LeadTableAction item={hit} selection={handleLeadDataSelection}/>
}
}
]
const columns = useMemo(()=>COLUMNS, []);
const tableInst = useTable({
columns,
data:props.lead.leadData ? props.lead.leadData : [{}]
}, useSortBy);
const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
prepareRow
} = tableInst;
On JSX:
<Table {...getTableProps()}>
<thead>
{headerGroups.map(hg=>{
return (
<tr {...hg.getHeaderGroupProps()}>
{hg.headers.map(h=>{
return (
<th {...h.getHeaderProps(h.getSortByToggleProps())}>
{h.render("Header")}
<span style={{marginLeft: '5px'}}>
{h.isSorted ? (h.isSortedDesc ? <i className="fas fa-sort-down"></i> : <i className="fas fa-sort-up"></i>) : ''}
</span>
</th>
)
})}
</tr>
)
})}
</thead>
<tbody {...getTableBodyProps()}>
{rows.map(row=>{
prepareRow(row)
return(
<tr {...row.getRowProps()}>
{row.cells.map(cell=>{
return(
<td {...cell.getCellProps()}>
{cell.render('Cell')}
</td>
)
})}
</tr>
)
})}
</tbody>
Can anybody help ?

Problem solved,
I just add a memo in my code:
const data = useMemo(()=>{
return props.lead.leadData ? props.lead.leadData : [{}]
}, [props.lead.leadData]);
This props.lead is the data to fetch direct on the table.
Done! :)

The whole time I tried passing an empty dependency array and my code did not throw any error there. It showed me errors only where I used hooks. I passed the data in the dependency hook in the useMemo array and it worked.
const data = useMemo(() => (employees.data), [employees.data]);

Related

Minified react error on react-table when changing accessor conditionally

I have a data from an API and I want to display it in a table. So I decided to use react-table since its light-weight and is 'headless'. Now, I need to display multiple values with conditionals in one of the columns but I got this error instead:
Maximum update depth exceeded. This can happen when a component repeatedly calls setState
inside componentWillUpdate or componentDidUpdate. React limits the number of nested
updates to prevent infinite loops.
This is my code:
const columns = useMemo(() => [
{
Header: 'Id',
accessor: 'station_id'
},
{
Header: 'Type',
accessor: 'type_name'
},
{
Header: 'Location',
accessor: 'location',
Cell: (cell) => (
<span>
{cell.row.original.location},
{(cell.row.original.barangay === null ? '' : (cell.row.original.barangay === "") ? '' : cell.row.original.barangay + ', ')}
{(cell.row.original.municipality === null ? '' : (cell.row.original.municipality === "") ? '' : cell.row.original.municipality + ', ')}
{cell.row.original.province}
</span>
)
},
]);
const data = useMemo(() => stations, [])
const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
prepareRow,
} = useTable({ columns, data })
return (
<div>
<table {...getTableProps()}>
<thead>
{headerGroups.map(headerGroup => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map(column => (
<th {...column.getHeaderProps()}>{column.render('Header')}</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{rows.map((row) => {
prepareRow(row)
return (
<tr {...row.getRowProps()}>
{row.cells.map((cell) => {
return <td {...cell.getCellProps()}>{cell.render('Cell')}</td>
})}
</tr>
)
})}
<tr>
<td></td>
</tr>
</tbody>
</table>
</div>
)
And this is the sample of my data:
{
"station_id": "0016782",
"location": "l-1",
"barangay": "Brgy-1",
"municipality": "",
"province": "RXI",
"type_name": "P-Sensor",
},
Then I want the table to look like this:
Id | Type | Location
0016782 | P-Sensor | l-1, Brgy-1, RXI
In your code, columns is missing dependency.
It causes an error.
const columns = useMemo(() => [
{
Header: 'Id',
accessor: 'station_id'
},
{
Header: 'Type',
accessor: 'type_name'
},
{
Header: 'Location',
accessor: 'location',
Cell: (cell) => (
<span>
{cell.row.original.location},
{(cell.row.original.barangay === null ? '' : (cell.row.original.barangay === "") ? '' : cell.row.original.barangay + ', ')}
{(cell.row.original.municipality === null ? '' : (cell.row.original.municipality === "") ? '' : cell.row.original.municipality + ', ')}
{cell.row.original.province}
</span>
)
},
], []);

react and react table: Problem with Maximum update depth exceeded

I'm getting this error when rendering a react-table in React typescript
caught Error: Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.
That is the code related to this:
import {useEffect, useMemo, useState} from "react";
import ManagementService from "../services/ManagementService";
import MasterSet from "../model/MasterSet";
import {Column, useTable} from "react-table";
const ShowMastersets: React.FC = () => {
const [mastersets, setMastersets] = useState<Array<MasterSet>>([]);
const [searchName, setSearchName] = useState("");
useEffect(() => {
retrieveMastersets();
}, []);
const columns: Array<Column<MasterSet>> = [
{
Header: "Masterset ID",
accessor: "mastersetId"
},
{
Header: "Masterset Name",
accessor: "mastersetName"
},
{
Header: "Key Name",
accessor: "keyName"
},
{
Header: "Key Start Time",
accessor: "keyStartTime"
}
];
const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
prepareRow
} = useTable({
columns,
data: mastersets
});
return (
<div className="list row">
<div className="col-md-12 list">
<table
className="table table-striped table-bordered"
{...getTableProps()}
>
<thead>
{headerGroups.map((headerGroup: any) => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map((column: any) => (
<th {...column.getHeaderProps()}>
{column.render("Header")}
</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{rows.map((row, i) => {
prepareRow(row);
return (
<tr {...row.getRowProps()}>
{row.cells.map((cell) => {
return (
<td {...cell.getCellProps()}>{cell.render("Cell")}</td>
);
})}
</tr>
);
})}
</tbody>
</table>
</div>
</div>
);
};
export default ShowMastersets;
Does anybody see what I am doing wrong? I have removed the parts of the controller which are not needed.
I would offer 2 suggestions to deal with this error: 1) create a type for your data, e.g.
export type MasterSet = {
mastersetId: string;
...
}
Then you can memoize it as follows:
const columns: Column<MasterSet>[] = useMemo(() => [
...
],[masterSet]);
turn autoResetPage to false in your useTable instance, like this:
...
const tableInstance: TableInstance = useTable(
{ columns, data, useSortBy, useExpanded,
initialState: { pageSize: 10, }, autoResetPage: false },
...allHooks
);
...
The latter especially should sort out the problem.

Toggle multiple buttons individually inside a react table

Inactive State:
Active State:
When I toggle a single button the state of every other button changes which I don't want. Is there any way to control the state of these toggles individually
This is my code for columns to be used in the table:
const COLUMNS = useMemo (() => [
{
Header: "Username",
accessor: "Username",
textAlign: "left",
sortable: false,
},
{
Header: "Status",
accessor: "Status",
textAlign: "center",
Cell: ({ value, cell: { row } }) => (
<div>
<FormControlLabel
control={
<IOSSwitch
checked={status}
onClick={toggler}
name="status"
/>
}
/>
{status ? <span>Active</span> : <span>Inactive</span>}
</div>
),
},
This is my code for the table:
<Table {...getTableProps()}>
<thead>
{headerGroups.map((headerGroup) => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map((column) => (
<Th
{...column.getHeaderProps({
style: { textAlign: column.textAlign },
})}
>
{column.render("Header")}
</Th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{page.map((row) => {
prepareRow(row);
return (
<Tr {...row.getRowProps()}>
{row.cells.map((cell) => {
return (
<Td
{...cell.getCellProps({
style: { textAlign: cell.column.textAlign },
})}
>
{cell.render("Cell")}
</Td>
);
})}
</Tr>
);
})}
</tbody>
</Table>
You have to assign each button to its individual state for example you can have three states for three buttons.
your states should look like this:
const [firstButton, setFirstButton] = useState(false)
const [secondButton, setSecondButton] = useState(false)
const [thirdButton, setThirdButton] = useState(false)
and in your onClicks you should say:
for example for second button:
onClick={()=>setSecondButton(false)}
and when you want to use this state in your table you should match every button with its state
ps: if your number of buttons are not fix, you should write a function to return an object which keys are button names and values are false ( false is default and this should change when clicks ).
Because of the immutability of states in react.js, you should clone the state and change what you want and leave every other thing as it is then update the whole state.
and use it like:
onClick={()=>setButtonsState({...buttonsState, secondButton:false})}
where buttonsState is like:
const [buttonsState, setButtonsState] = useState(
{
firstButton: false,
secondButton: false,
thirdButton: false
}
)

Regular react table to MaterialTable

How can I add data in my Material Table from an array?
I have the following table:
<table className="table">
<thead>
<tr>
<th>Text1</th>
<th>Text2</th>
<th>text3 Comb</th>
</tr>
</thead>
<tbody>
{arr.map((values, index) => {
const textComb = `${values.text1}, ${values.text2}`;
return (
<tr key={index}>
<td>{values.text1}</td>
<td>{values.text2}</td>
<td>{textComb}</td>
<td></td>
</tr>
)
})}
</tbody>
</table>
I have too many data, so I'm trying to use MaterialTable to have a search, sort, and pagination option.
<MaterialTable
columns={[
{title: 'Text1', field: 'text1'},
{title: 'Text2', field: 'text2'},
{title: 'Text3', field: 'text3'}
]}
data={
arr((values, index) => {
{
// I'm confused here
}
})
}
/>
try this-
const createData = item => ({
text1: item.text1,
text2: item.text2,
text3: `${item.text1}, ${item.text2}`
});
const data = arr.map(item => createData(item));
check demo here - https://codesandbox.io/s/material-table-example-5cohx?file=/src/App.js

Getting Information/Data/Values from a row in React-Table

I literally have stayed up all night trying to figure out how to grab a value from my row.
const columns = useMemo(
() => [
{
// first group - TV Show
Header: "Shop Chop Chop List",
// First group columns
columns: [
{
Header: "User",
accessor: "email",
},
{
Header: "Store",
accessor: "store",
},
],
},
{
Header: "Details",
columns: [
{
Header: "Item",
accessor: "title",
},
{
Header: "Picture",
accessor: "picture",
Cell: ({ row }) => (
<a
target="_blank"
rel="noopener noreferrer"
href={row.original.picture}
>
{row.original.picture}
</a>
),
},
{
Header: "Aisle",
accessor: "aisleLocation",
},
{
Header: "Location",
id: 'edit',
accessor: 'id',
Cell: ({value}) => (
<div>
<button
onClick={()=> {
console.log(value);
}}
className={styles.editBtn}
>
Record Aisle
</button>
</div>
),
},
{
Header: "Remove",
id: "delete",
accessor: (str) => "delete",
Cell: (row)=> (
<button
className={styles.deleteBtn}
onClick={()=> {
const dataCopy = [...data];
dataCopy.splice(row.index, 1);
setData(dataCopy);
}}>
Found
</button>
)
}
],
},
],
[data],
);
This is my latest attempt. I am trying to grab a value from this row so I can assign a aisle location on the back end. I would prefer the uniqueID, but I could make it work with title and store as well. It is so damn hard to grab the information out of this row.
Here is my tableContainer
import React, { Fragment } from 'react';
import {
useTable,
useSortBy,
useFilters,
useExpanded,
usePagination,
} from 'react-table';
import { Table, Row, Col, Button, Input} from 'reactstrap';
import { Filter, DefaultColumnFilter } from './Filters';
const TableContainer = ({ columns, data, renderRowSubComponent }) => {
const {
getTableProps,
getTableBodyProps,
headerGroups,
page,
prepareRow,
visibleColumns,
canPreviousPage,
canNextPage,
pageOptions,
pageCount,
gotoPage,
nextPage,
previousPage,
state: { pageIndex },
} = useTable(
{
columns,
data,
defaultColumn: { Filter: DefaultColumnFilter },
initialState: { pageIndex: 0, pageSize: 5 },
},
useFilters,
useSortBy,
useExpanded,
usePagination
);
const generateSortingIndicator = (column) => {
return column.isSorted ? (column.isSortedDesc ? ' 🔽' : ' 🔼') : '';
};
const onChangeInInput = (event) => {
const page = event.target.value ? Number(event.target.value) - 1 : 0;
gotoPage(page);
};
return (
<Fragment>
<Table bordered hover {...getTableProps()}>
<thead>
{headerGroups.map((headerGroup) => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map((column) => (
<th {...column.getHeaderProps()}>
<div {...column.getSortByToggleProps()}>
{column.render('Header')}
{generateSortingIndicator(column)}
</div>
<Filter column={column} />
</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{page.map((row) => {
prepareRow(row);
return (
<Fragment key={row.getRowProps().key}>
<tr onClick={()=> handleShow(row.original)}>
{row.cells.map((cell) => {
return (
<td {...cell.getCellProps()}>{cell.render('Cell')}</td>
);
})}
</tr>
{row.isExpanded && (
<tr>
<td colSpan={visibleColumns.length}>
{renderRowSubComponent(row)}
</td>
</tr>
)}
</Fragment>
);
})}
</tbody>
</Table>
Please, can anyone help? I am new so very specific instructions are desired
please, and thank you
react-table is meant for displaying the data, not the JSX element but you can solve the issue in two ways, first, you can pass a unique id in the row data and just like above use that in the Cell or you can just render the JSX element as a row data and use the unique id directly(for example some model Id which you are trying to delete) but rendering the JSX element as a data is a heavy task as memoization will fail and you will have to do provide extra logic to prevent rerendering.

Resources