Search code examples
reactjsuse-effectreact-tablereact-table-v7

UseEffect with React-Table not displaying changes unless the page is refreshed


I am a Java developer trying to learn React and I have this issue where I updated a table to use react-table and now, whenever I either add or delete an item from my api response, I need to refresh the whole page to see the changes take place, whereas before I had my useEffect showing these changes immediately.

Below I have my complete piece of code after deleting pretty much everything else trying to find the root cause for this issue. If I use the commented out tbody instead of the one that uses react-table, I can still see my updates working fine and as expected.

It may be worth mentioning also that if I try to use setData inside of the useEffect piece the react-table won't even get populated.

const {useTable} = require('react-table')

const MainTable = ({dataTableObj}) => {

const [reports, setReports] = useState(dataTableObj.reports)

const getInitialData = () => reports.map(report => ({
    name: report.title,
    runDate: report.runDate,
    createdDate: report.createdDate,
    category: report.category.title,
    actions: report.id,
}));

const [data, setData] = useState(getInitialData)

const {
    getTableProps,
    getTableBodyProps,
    rows,
    prepareRow,
} = useTable(
    {
        columns,
        data,
    }
);

useEffect(() => {

    setReports(dataTableObj.reports)
    // setData(dataTableObj.reports)

}, [dataTableObj.reports]);

const onConfirmDelete = (id) => {

    deleteReport(id).then(() => {

        const del = reports.filter(report => id !== report.id)
        setReports(del)

    })
}

return (
    <div>
        <table {...getTableProps()}>
            <tbody {...getTableBodyProps()}>
            {rows.map((row, i) => {
                prepareRow(row)
                return (
                    <tr {...row.getRowProps()}>
                        <td>{row.original.name}</td>
                        <td>
                            <IconButton onClick={() => onConfirmDelete(row.original.actions)}>
                                <Delete/>
                            </IconButton>
                        </td>
                    </tr>
                )
            })}
            </tbody>
            {/*<tbody>*/}
            {/*{reports.map((item) => {*/}
            {/*    return [*/}
            {/*        <tr key={item.id}>*/}
            {/*            <td>{item.title}</td>*/}
            {/*            <td>*/}
            {/*                <IconButton onClick={() => onConfirmDelete(item.id)}>*/}
            {/*                    <Delete/>*/}
            {/*                </IconButton>*/}
            {/*            </td>*/}
            {/*        </tr>*/}
            {/*    ];*/}
            {/*})}*/}
            {/*</tbody>*/}
        </table>
    </div>
    )
}

export default MainTable

I think I've run out of ideas at this point on what I could be missing and may need some help or guidance please.

Thank you very much.


Solution

  • I made this codesandbox to test: https://codesandbox.io/s/confident-drake-e47wm?file=/src/MainTable.js

    If you toggle line 9 and 10 in MainTable.js, you will toggle it working and not working. It seems when you put the data into local state (as you do because you are mapping it), it won't re-render. Not exactly sure why this is, I've never used react-table, maybe it's in the docs somewhere.

    So I think you will either need to:

    1. do the mapping in the parent and pass the data into MainTable already mapped, or
    2. wrap MainTable in another component that does the mapping and again pass the data into MainTable already mapped
    3. Maybe it could be done with a custom hook, I didn't try that.