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>
)
},
], []);
Related
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
}
)
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]);
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.
How to pass data values as a parameter in React Table version 7.
I was trying to pass status and id in butFunction inside of react table so that i can create a function which create a button opposite of the status .
here is code what i had tried to do so.
Demo Link of the same code
const data = [
{ firstName: "Jane", lastName: "Doe", status: "OPEN" , id: "1" },
{ firstName: "John", lastName: "Smith", status: "CLOSE" , id: "2" },
{ firstName: "John", lastName: "Walker", status: "OPEN" , id: "3" }
];
const columns = [
{
Header: "First Name",
accessor: "firstName"
},
{
Header: "Last Name",
accessor: "lastName"
},
{
Header: "Status",
accessor: "status"
}
];
const Table = ({ columns, data }) => {
const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
prepareRow
} = useTable({
columns,
data
});
const butFunction = (level , id) => {
console.log(level)
console.log(id)
if (level === "OPEN") {
return <button > CLOSE </button>;
} else {
return <button > OPEN </button>;
}
};
return (
<table {...getTableProps()}>
<thead>
{headerGroups.map(headerGroup => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map(column => (
<th {...column.getHeaderProps()}>{column.render("Header")}</th>
))}
<th>Action</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>;
})}
<td>{butFunction(data.status, data.id)}</td>
</tr>
);
})}
</tbody>
</table>
);
};
export default function App() {
return (
<div className="App">
<Table columns={columns} data={data} />
</div>
);
}
You need to access row.values to access the data for each row. Inside the map function, row.values will be an object that contains the data for the current row.
Edit:
As per your comment, row.values object doesn't contains id property of your data objects. To access the id, use row.original.id
<td>{ butFunction(row.values.status, row.original.id) }</td>
Hi I am working on react, and i one problem in which i have one dynamically generated table and i want the first column of my table to be clickable and navigate to another page.
eg: Here in the below array i have 3 fields in which name should be clickable and onclick of this field it will navigate to the another page.
tableData: [
{id: "1", name: "name1", value: "1" },
{id: "2", name: "name2", value: "2"}
]
I the below method getBody() takes the data as props in which when i return the row it will return the above array.
eg:
getBody = () => {
return this.props.body.map((row, index) => {
return (
<tr key={index}>
{this.renderRowData(row)}
</tr>
)
});
}
renderRowData = (row) => {
return this.props.header.map(({ key, checked }, index) => {
return (
<td key={index}
className={(key === 'status' ? this.getStatusColor(row[key]) : '') ||
(key === 'rule_type' ? this.getRuleTypeColor(row[key]) : '')}>
<div className="item">
{
(checked)
? <CheckBox
checked={this.props.selectedValue && this.props.selectedValue.indexOf(row[key]) >= 0}
clicked={() => this.props.onChecked(row[key])} />
: null
}
{
this.props.noPrecision === 'true' ?
<span className="checkbox-design">{roundOff(row[key], 0)}</span> :
<span className="checkbox-design">{roundOff(row[key], 2)}</span>
}
</div>
</td>
);
});
};
export const header = [
{
key: 'name',
value: 'Name',
checked: true,
},
So here i want to return the row in such a way that its first row should be clickable and navigate to another page.
you can render the first column of the table as a react-router Link
For example
tableData: [
{id: "1", name: "name1", value: "1" },
{id: "2", name: "name2", value: "2"}
]
function Table() {
return (
<table>
<thead><tr>
<th>Name</th>
<th>Value</th>
</tr>
</thead>
<tbody>
{tableData.map(r => {
<tr key={r.id} >
<td>
<Link to={name}>{name}</Link>
</td>
<td>
{value}
</td>
</tr>
})}
</tbody>
</table>
)
}
For reference on using react-router link you can refer this link
You can refer to this sandbox
renderRowData = (row) => {
return this.props.header.map(({ key, checked }, index) => {
const rowEl = (
<div className="item">
{
(checked)
? <CheckBox
checked={this.props.selectedValue && this.props.selectedValue.indexOf(row[key]) >= 0}
clicked={() => this.props.onChecked(row[key])} />
: null
}
{
this.props.noPrecision === 'true' ?
<span className="checkbox-design">{roundOff(row[key], 0)}</span> :
<span className="checkbox-design">{roundOff(row[key], 2)}</span>
}
</div>
)
return (
<td key={index}
className={(key === 'status' ? this.getStatusColor(row[key]) : '') ||
(key === 'rule_type' ? this.getRuleTypeColor(row[key]) : '')}>
{key === 'name' ? <Link to={name}>{rowEl}</Link> : rowEl}
</td>
);
});
};
You can use history inside the onClick handle:
if (props.history) props.history.push('/otherpage');