最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Why memory leak happend and render slowing down when I close and re-open react component (material-table)? - Stack

programmeradmin1浏览0评论

I have basic react example for learning and I use material-table in one of my ponents. Each time I change the page and re-open it (unmount and mount ponent), my ponent which contains material-table load more slowly. I share my code below.


import MaterialTable from 'material-table';

const columns = [
    { title: 'Id', field: 'id', hidden: true },
    { title: 'Username', field: 'username' },
    { title: 'Name', field: 'name' },
    { title: 'Phone', field: 'phone'}
];

const tableData = [
    {
        id: 1,
        username: "User-1",
        name: "name-1",
        phone: "555 444 33 22"
    },
    {
        id: 2,
        username: "User-2",
        name: "name-2",
        phone: "111 222 33 44"
    },
    {
        id: 3,
        username: "User-3",
        name: "name-3",
        phone: "999 999 99 99"
    }
];

const MTable = () => {
    return (
        <MaterialTable 
            title="Basic Search Preview"
            columns={columns}
            data={tableData}
            options={{search: true }}
        />
    )
}

export default MTable


After long search I did not find any solution, and after long try I just change the place of columns definition like below.


const MTable = () => {

    const columns = [
        { title: 'Id', field: 'id', hidden: true },
        { title: 'Username', field: 'username' },
        { title: 'Name', field: 'name' },
        { title: 'Phone', field: 'phone'}
    ];

    return (
        <MaterialTable 
            title="Basic Search Preview"
            columns={columns}
            data={tableData}
            options={{search: true }}
        />
    )
}

This change solve my problem but I really want to learn why this happened. When I made the column definition outside of the method why memory leak and render slowed each page change. At the same time, when I moved into method what changed?

I have basic react example for learning and I use material-table in one of my ponents. Each time I change the page and re-open it (unmount and mount ponent), my ponent which contains material-table load more slowly. I share my code below.


import MaterialTable from 'material-table';

const columns = [
    { title: 'Id', field: 'id', hidden: true },
    { title: 'Username', field: 'username' },
    { title: 'Name', field: 'name' },
    { title: 'Phone', field: 'phone'}
];

const tableData = [
    {
        id: 1,
        username: "User-1",
        name: "name-1",
        phone: "555 444 33 22"
    },
    {
        id: 2,
        username: "User-2",
        name: "name-2",
        phone: "111 222 33 44"
    },
    {
        id: 3,
        username: "User-3",
        name: "name-3",
        phone: "999 999 99 99"
    }
];

const MTable = () => {
    return (
        <MaterialTable 
            title="Basic Search Preview"
            columns={columns}
            data={tableData}
            options={{search: true }}
        />
    )
}

export default MTable


After long search I did not find any solution, and after long try I just change the place of columns definition like below.


const MTable = () => {

    const columns = [
        { title: 'Id', field: 'id', hidden: true },
        { title: 'Username', field: 'username' },
        { title: 'Name', field: 'name' },
        { title: 'Phone', field: 'phone'}
    ];

    return (
        <MaterialTable 
            title="Basic Search Preview"
            columns={columns}
            data={tableData}
            options={{search: true }}
        />
    )
}

This change solve my problem but I really want to learn why this happened. When I made the column definition outside of the method why memory leak and render slowed each page change. At the same time, when I moved into method what changed?

Share Improve this question asked Sep 16, 2021 at 20:13 ChivalrouSChivalrouS 2063 silver badges14 bronze badges 4
  • this doesn't make any sense, actually the second version should be in theory slower :) btw slow <> memory leak, there must be something else which caused this. – windmaomao Commented Sep 16, 2021 at 22:33
  • Actually I thougth the same way. That is why, finding the solution took my long time. You can basically try two version of this and you will see the problem. Each time you unmount and mount the ponent, It will take more time. @windmaomao – ChivalrouS Commented Sep 16, 2021 at 22:40
  • @windmaomao In addition, Its really ate my all memory :) – ChivalrouS Commented Sep 16, 2021 at 23:08
  • 2 I do confirm this behavior. When mounting / unmounting repeatedly with e.g. { !show ? null : <MTable /> } it took approx. 50, 70, 130, 870, 8020 milliseconds to build the MaterialTable. – kca Commented Sep 17, 2021 at 22:36
Add a ment  | 

3 Answers 3

Reset to default 6

analysis

material-table adds a property column.tableData to each column of your columns list, and then there is an assignment that effectively does something like (see file data-manager.js):

column[0].tableData.width = "calc(" + ... +
  column[0].tableData.width + ... +
  column[1].tableData.width + ... + ")"

column[1].tableData.width = "calc(" + ... 
...

Because the columns are in the global scope and are not destroyed on every unmount, this lets the string tableData.width grow exponentially. I guess the increasingly long time it takes es from these increasingly many nested "calc()" invocations.

conclusion

I hesitate to call this a bug in material-table.

It looks like material-table expects the columns to be created on every render (and not to be persistent). Fair enough, but I would at least call this unexpected behavior for somebody who is used to work in React, and there should be a warning about this in the documentation. I also think even then that could have been implemented foolproof. (if somebody disagrees, I'd like to read reasons in the ments)

example

The first time the ponent is mounted the tableData.width is:

calc((100% - (0px +
  calc((100% - (0px)) / 3) +
  calc((100% - (0px)) / 3) +
  calc((100% - (0px)) / 3)
)) / 3)

After un-mount and a second mount the width tableData.width is:

calc((100% - (0px +
  calc((100% - (0px + 
    calc((100% - (0px + calc((100% - (0px)) / 3) + calc((100% - (0px)) / 3) + calc((100% - (0px)) / 3))) / 3) + 
    calc((100% - (0px + calc((100% - (0px)) / 3) + calc((100% - (0px)) / 3) + calc((100% - (0px)) / 3))) / 3) + 
    calc((100% - (0px + calc((100% - (0px)) / 3) + calc((100% - (0px)) / 3) + calc((100% - (0px)) / 3))) / 3)
  )) / 3) +
  calc((100% - (0px + 
    calc((100% - (0px + calc((100% - (0px)) / 3) + calc((100% - (0px)) / 3) + calc((100% - (0px)) / 3))) / 3) + 
    calc((100% - (0px + calc((100% - (0px)) / 3) + calc((100% - (0px)) / 3) + calc((100% - (0px)) / 3))) / 3) + 
    calc((100% - (0px + calc((100% - (0px)) / 3) + calc((100% - (0px)) / 3) + calc((100% - (0px)) / 3))) / 3)
  )) / 3) +
  calc((100% - (0px + 
    calc((100% - (0px + calc((100% - (0px)) / 3) + calc((100% - (0px)) / 3) + calc((100% - (0px)) / 3))) / 3) + 
    calc((100% - (0px + calc((100% - (0px)) / 3) + calc((100% - (0px)) / 3) + calc((100% - (0px)) / 3))) / 3) + 
    calc((100% - (0px + calc((100% - (0px)) / 3) + calc((100% - (0px)) / 3) + calc((100% - (0px)) / 3))) / 3)
  )) / 3)
)) / 3)"

The columns array should be static to a material table instance. When it is dynamically called again and again, the memory fills and finally runs out of space.

If you try to use useState to manage the columns this issue will happen. I had a workaround where I would set the columns each time which worked but would reset my groupings, etc.

There is a fork of material-table which solves that issue:https://material-table-core./docs/#installation

npx create-react-app material-table-app
npm uninstall react react-dom
npm install [email protected] [email protected] 
npm install @material-table/[email protected] --legacy-deps 

This is the bination that worked for me. Using this setup I can use useState to set my columns/maintain their state.

I was getting a _deepmerge issue with material-table ^5.0 that I couldn't resolve. Almost just gave up entirely on this package.

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论