I am using react-table to display fetched data within a table. You also have different buttons within that table to interact with the data such as deleting an entry, or updating its data (toggle button to approve a submitted row).
The data is being fetched in an initial useEffect(() => fetchBars(), []) and then being passed to useTable by passing it through useMemo as suggested in the react-table documentation. Now I can click on the previously mentioned buttons within the table to delete an entry but when I try to access the data (bars) that has been set within fetchBars()it returns the default state used by useState() which is an empty array []. What detail am I missing? I want to use the bars state in order to filter deleted rows for example and thus make the table reactive, without having to re-fetch on every update.
When calling console.log(bars) within updateMyData() it displays the fetched data correctly, however calling console.log(bars) within handleApprovedUpdate() yields to the empty array, why so? Do I need to pass the handleApprovedUpdate() into the cell as well as the useTable hook as well?
const EditableCell = ({
value: initialValue,
row: { index },
column: { id },
row: row,
updateMyData, // This is a custom function that we supplied to our table instance
}: CellValues) => {
const [value, setValue] = useState(initialValue)
const onChange = (e: any) => {
setValue(e.target.value)
}
const onBlur = () => {
updateMyData(index, id, value)
}
useEffect(() => {
setValue(initialValue)
}, [initialValue])
return <EditableInput value={value} onChange={onChange} onBlur={onBlur} />
}
const Dashboard: FC<IProps> = (props) => {
const [bars, setBars] = useState<Bar[]>([])
const [loading, setLoading] = useState(false)
const COLUMNS: any = [
{
Header: () => null,
id: 'approver',
disableSortBy: true,
Cell: (props :any) => {
return (
<input
id="approved"
name="approved"
type="checkbox"
checked={props.cell.row.original.is_approved}
onChange={() => handleApprovedUpdate(props.cell.row.original.id)}
/>
)
}
}
];
const defaultColumn = React.useMemo(
() => ({
Filter: DefaultColumnFilter,
Cell: EditableCell,
}), [])
const updateMyData = (rowIndex: any, columnId: any, value: any) => {
let barUpdate;
setBars(old =>
old.map((row, index) => {
if (index === rowIndex) {
barUpdate = {
...old[rowIndex],
[columnId]: value,
}
return barUpdate;
}
return row
})
)
if(barUpdate) updateBar(barUpdate)
}
const columns = useMemo(() => COLUMNS, []);
const data = useMemo(() => bars, [bars]);
const tableInstance = useTable({
columns: columns,
data: data,
initialState: {
},
defaultColumn,
updateMyData
}, useFilters, useSortBy, useExpanded );
const fetchBars = () => {
axios
.get("/api/allbars",
{
headers: {
Authorization: "Bearer " + localStorage.getItem("token")
}
}, )
.then(response => {
setBars(response.data)
})
.catch(() => {
});
};
useEffect(() => {
fetchBars()
}, []);
const handleApprovedUpdate = (barId: number): void => {
const approvedUrl = `/api/bar/approved?id=${barId}`
setLoading(true)
axios
.put(
approvedUrl, {},
{
headers: {Authorization: "Bearer " + localStorage.getItem("token")}
}
)
.then(() => {
const updatedBar: Bar | undefined = bars.find(bar => bar.id === barId);
if(updatedBar == null) {
setLoading(false)
return;
}
updatedBar.is_approved = !updatedBar?.is_approved
setBars(bars.map(bar => (bar.id === barId ? updatedBar : bar)))
setLoading(false)
})
.catch((error) => {
setLoading(false)
renderToast(error.response.request.responseText);
});
};
const renderTable = () => {
const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
prepareRow
} = tableInstance;
return(
<table {...getTableProps()}>
<thead>
{headerGroups.map(headerGroup => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map(column => (
<th {...column.getHeaderProps()}>
<span {...column.getSortByToggleProps()}>
{column.render('Header')}
</span>{' '}
<span>
{column.isSorted ? column.isSortedDesc ? ' ▼' : ' ▲' : ''}
</span>
<div>{column.canFilter ? column.render('Filter') : <Spacer/>}</div>
</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{rows.map(row => {
prepareRow(row)
const rowProps = {...row.getRowProps()}
delete rowProps.role;
return (
<React.Fragment {...rowProps}>
<tr {...row.getRowProps()}>
{row.cells.map(cell => {
return (
<td {...cell.getCellProps()}>{cell.render('Cell')}</td>
)
})}
</tr>
{row.isExpanded ? renderRowSubComponent({row}): null}
</React.Fragment>
)})
}
</tbody>
</table>
)
}
}
export default Dashboard;