reactjsnext.jsmaterial-ui

Material table slows after several data changes


So, I have fetchData() function that updates data everytime I clicked next or previous page button (basically, every page change). Here's the snippet

const fetchData = (limit, offset) => {
    const token = localStorage.getItem("token");
    const body = {
        ...(keyword ? { keyword } : {}),
        limit,
        offset,
        minify: true,
    };

    axiosUtil
        .request("POST", body.keyword ? "/blocker/private/user/popup-search" : "/blocker/private/user/popup-all", body, token)
        .then((data) => {
            const result = data.data ?? data;

            let startTime = performance.now();
            console.log("Mapping data...");
            const mapped = result.map((e) => {
                let color = "#36AE7C";
                let text = "Enable Popup";
                let icon = "CheckCircleOutlineIcon";
                if (e.is_disabled != true) {
                    color = "#E23E57";
                    text = "Disabled Popup";
                    icon = "CancelIcon";
                }

                if (e.interval) {
                    e.type = <Chip label="Repeating Response" color="secondary" />;
                } else {
                    e.type = <Chip label="Single Response" color="primary" />;
                }

                e.color = color;
                e.icon = icon;
                e.text = text;

                e.filter_parent = Object.keys(e.filter).toString().replace(/,/g, ", ");
                e.date = moment(e.createdAt).format("D MMMM YYYY");
                e.action = (
                    <>
                        <ButtonGroup variant="contained" color="primary" size="small">
                            <Tooltip title="View Detail">
                                <IconButton color="primary" onClick={() => handleOpen(e.id)}>
                                    <VisibilityIcon />
                                </IconButton>
                            </Tooltip>
                            <Tooltip title={e.text}>
                                <IconButton style={{ color: e.color }} onClick={() => handleDisable(e.id, e.is_disabled)}>
                                    <PowerSettingsNewIcon />
                                </IconButton>
                            </Tooltip>
                            <Tooltip title="View Response">
                                <IconButton style={{ color: "#4D77FF" }} onClick={() => handleResponse(e.id, e.title, e.interval)}>
                                    <ListAltIcon />
                                </IconButton>
                            </Tooltip>
                            <Tooltip title="Remove message">
                                <IconButton style={{ color: "#E23E57" }} onClick={() => handleRemove(e.id)}>
                                    <DeleteOutline />
                                </IconButton>
                            </Tooltip>
                        </ButtonGroup>
                    </>
                );
                return e;
            });
            let endTime = performance.now();
            let executionTime = endTime - startTime; // in milliseconds with higher precision
            console.log(`Execution time: ${executionTime.toFixed(3)} ms`);

            startTime = performance.now();
            console.log("Setting data...");
            fetchCountPopup();
            unstable_batchedUpdates(() => {
                setData(mapped);
            });
            endTime = performance.now();
            executionTime = endTime - startTime; // in milliseconds with higher precision
            console.log(`Execution time: ${executionTime.toFixed(3)} ms`);
        })
        .catch((e) => {
            console.log(e);
            logout();
        });
};

I've logged the execution time and found out that the mapping operation is not the problem and setData() function takes more time after changing the page several time enter image description here

Then I commented data={data} on my MaterialTable component and the spike on setData()'s execution time is gone

<MaterialTable
    className={classes.root}
    icons={tableIcons}
    title="Released Popup"
    columns={columns}
    style={{ marginTop: 10 }}
    data={data}
    options={{
        search: false,
    }}
    components={{
        Pagination: (props) => (
            <TablePagination
                {...props}
                rowsPerPage={numberRowPerPage}
                count={totalPopup}
                page={pageNumber - 1}
                onChangePage={(e, page) => handleChangePage(page + 1)}
                onChangeRowsPerPage={(event) => {
                    props.onChangeRowsPerPage(event);
                    handleChangeRowPerPage(event.target.value);
                }}
            />
        ),
    }}
/>

And there's also spike on memory usage enter image description here

My conclusion is it caused by the MaterialTable rerendering. How do I fix that? I'm using "material-table": "^1.68.1"


Solution

  • Solved by hardcoding columns into MaterialTable component directly since there is a memory leak bug for dynamic columns.

    <MaterialTable
        ...
        columns={[
            { title: "Title", field: "title" },
            { title: "Filter", field: "filter_parent" },
            { title: "Type", field: "type" },
            { title: "Created by", field: "created_by" },
            { title: "Created at", field: "date" },
            { title: "Action", field: "action" },
        ]}
        style={{ marginTop: 10 }}
        data={data}
        options={{
            search: false,
        }}
        ...
    />
    

    instead of

    <MaterialTable
        ...
        columns={columns}
        style={{ marginTop: 10 }}
        data={data}
        options={{
            search: false,
        }}
        ...
    />