x13
x13

Reputation: 33

Async fetch of data not rerendering ReactJS datatable(or just not displaying new data)

The problem here is that, if my new data is fetched from my backend(RestAPI), the datatable does not display the new data even though I called this.setState and if I log the new state, the fetched data gets logged to the console, but is not displayed in my datatable. When I hardcode the data in the constructors this.state = xxx, the data gets displayed just fine. So I think this has to be related to some rerendering problem? I debugged for hours, but I just couldn't find the problem. It would be really great if somebody could help me out here :)

I read very much articles and posts about not rerendering and the lifecycle of react components. As further info, when I log the state in the render method before the return values, it is at first null (as I initialised the state), and after the second rendering the data is in this.state.rowData as desired. But I simply cant find out why it doesnt get displayed in the datatable.


    constructor(props) {
        super(props);
        this.state = {
            columnDefs: [{
                headerName: "Dump Name", field: "dumpName", sortable: true, filter: true
            }, {
                headerName: "Type", field: "type", sortable: true, filter: true
            }, {
                headerName: "Size", field: "length", sortable: true, filter: true
            }, {
                headerName: "Different CAN-IDs", field: "canIdCount", sortable: true, filter: true
            }, {
                headerName: "Created At", field: "createdAt", sortable: true, filter: true
            }],
            rowData: null
        }
    }

    componentDidMount = async () => {
        let collectionData = [];
        await getSniffs().then(function (sniffdata) {
            sniffdata.map(async function (row) {
                collectionData.push({
                    dumpName: row,
                    length: await getMessageCount(row).then(function (res) {
                        return res[0].all;
                    }),
                    canIdCount: await getIdCountDistinct(row).then(function (res) {
                        return res[0].count;
                    }),
                    createdAt: await getFirstTimestamp(row).then(function (res) {
                        return res[0].firstTimestamp;
                    }),
                    type: "CAN Message"
                });
            });
        }).then(() => this.setState({
            rowData: collectionData
        }));
    };

    render() {
        console.log(this.state);
        return (
            <div
                className="ag-theme-material"
                style={{
                    height: '500px',
                    width: '1000px' }}
            >
                <AgGridReact
                    // onRowClicked={this.onRowClicked.bind(this)}
                    columnDefs={this.state.columnDefs}
                    rowData={this.state.rowData}>
                </AgGridReact>
            </div>
            // : <Loading/>;
    )}
}

export default withRouter(SniffOverviewDatatable);

The datatable just shows: No Row to show. At first I think thats the correct result, but it should get updated and show my retrieved data. The logs display exactly the desired data and array-structure.

Thanks for your time and I really hope to get some hints :)

EDIT: Hey hey I just rewrote the componentDidMount function, but it didnt change a thing, im afraid. Data gets logged, but table doesnt get updated :/

Here is the new code of the function (used async/await):

componentDidMount = async () => {
            let rowData = [];
            try {
                const sniffs = await getSniffs();
                sniffs.map(async function (row) {
                    const msgCount = await getMessageCount(row);
                    const idCount = await getIdCountDistinct(row);
                    const firstTimestamp = await getFirstTimestamp(row);

                    rowData.push({
                        dumpName: row,
                        length: msgCount[0].all,
                        canIdCount: idCount[0].count,
                        createdAt: firstTimestamp[0].firstTimestamp,
                        type: "CAN Message"
                    });
                });
            } catch (e) {
                console.log(e);
            }
            this.setState({
                rowData
            });
        };

Upvotes: 0

Views: 677

Answers (2)

x13
x13

Reputation: 33

Hello I just wanted to provide my own answer if anybo0dy looks at this question:

    componentDidMount = async () => {
    let fetched = await getSniffs();

    let rowData = [];

    for (const row of fetched.data) {
        const msgCount = await getMessageCount(row);
        const idCount = await getIdCountDistinct(row);
        const firstTimestamp = await getFirstTimestamp(row);

        rowData.push({
            dumpName: row,
            length: msgCount.data[0].all,
            canIdCount: idCount.data[0].count,
            createdAt: new Date(firstTimestamp.data[0].firstTimestamp),
            type: "CAN Message"
        });
    }

    this.setState({
        rowData
    });
};

This works just fine now :) I also migrated this method one Component above, so the datatable just gets its data via the props and not via state. Thanks and closed!

Upvotes: 0

Basti
Basti

Reputation: 11

Have you already tried using setState with a callback function and some kind of immutability library such as immutability-helper? This would lead to code like this:

import update from 'immutability-helper';
...

this.setState(prevState => update(prevState, {rowData: {$set: collectionData}});
...

Upvotes: 1

Related Questions