Material-UI Data Grid onSortModelChange Causing an Infinite Loop

Viewed 2805

I'm following the Sort Model documentation (https://material-ui.com/components/data-grid/sorting/#basic-sorting) and am using sortModel and onSortModelChange exactly as used in the documentation. However, I'm getting an infinite loop immediately after loading the page (I can tell this based on the console.log).

What I've tried:

I always end up with the same issue. I'm using Blitz.js.

My code:

useState:

const [sortModel, setSortModel] = useState<GridSortModel>([
    {
      field: "updatedAt",
      sort: "desc" as GridSortDirection,
    },
  ])

rows definition:

  const rows = currentUsersApplications.map((application) => {
    return {
      id: application.id,
      business_name: application.business_name,
      business_phone: application.business_phone,
      applicant_name: application.applicant_name,
      applicant_email: application.applicant_email,
      owner_cell_phone: application.owner_cell_phone,
      status: application.status,
      agent_name: application.agent_name,
      equipment_description: application.equipment_description,
      createdAt: formattedDate(application.createdAt),
      updatedAt: formattedDate(application.updatedAt),
      archived: application.archived,
    }
  })

columns definition:


  const columns = [
    { field: "id", headerName: "ID", width: 70, hide: true },
    {
      field: "business_name",
      headerName: "Business Name",
      width: 200,
      // Need renderCell() here because this is a link and not just a string
      renderCell: (params: GridCellParams) => {
        console.log(params)
        return <BusinessNameLink application={params.row} />
      },
    },
    { field: "business_phone", headerName: "Business Phone", width: 180 },
    { field: "applicant_name", headerName: "Applicant Name", width: 180 },
    { field: "applicant_email", headerName: "Applicant Email", width: 180 },
    { field: "owner_cell_phone", headerName: "Ownership/Guarantor Phone", width: 260 },
    { field: "status", headerName: "Status", width: 130 },
    { field: "agent_name", headerName: "Agent", width: 130 },
    { field: "equipment_description", headerName: "Equipment", width: 200 },
    { field: "createdAt", headerName: "Submitted At", width: 250 },
    { field: "updatedAt", headerName: "Last Edited", width: 250 },
    { field: "archived", headerName: "Archived", width: 180, type: "boolean" },
  ]

Rendering DataGrid and using sortModel/onSortChange

      <div style={{ height: 580, width: "100%" }} className={classes.gridRowColor}>
        <DataGrid
          getRowClassName={(params) => `MuiDataGrid-row--${params.getValue(params.id, "status")}`}
          rows={rows}
          columns={columns}
          pageSize={10}
          components={{
            Toolbar: GridToolbar,
          }}
          filterModel={{
            items: [{ columnField: "archived", operatorValue: "is", value: showArchived }],
          }}
          sortModel={sortModel}
          onSortModelChange={(model) => {
            console.log(model)
            //Infinitely logs model immediately
            setSortModel(model)
          }}
        />
      </div>

Thanks in advance!

4 Answers

I fixed this by wrapping rows and columns in useRefs and used their .current property for both of them. Fixed it immediately.

Could not understand what the top post meant by using useRef, but the below solution is what worked for me:

    const [sortModel, setSortModel] = useState<GridSortModel>([
        {
            field: 'created',
            sort: 'desc',
        },
    ]);

    const handleSortChange = (model: GridSortModel) => {
        /* if statement to prevent the infinite loop by confirming model is 
         different than the current sortModel state */
        if (JSON.stringify(model) !== JSON.stringify(sortModel)) {
            setSortModel(model);
        }
    };

    <DataGrid
    rows={taskData}
    columns={myWorkColumns}
    sortModel={sortModel}
    onSortModelChange={(model) => handleSortChange(model)}
    />

experienced this issue also recently. here's how i was able to fix it.

handleSortChange = (model) => {
  let dgSort = model[0];
  if (JSON.stringify(this.state.dgSort) !== JSON.stringify(dgSort)){
    console.log("new sort", dgSort);
    this.setState({
      dgSort: dgSort
    });
  }
}

For some reason, adding a condition just before setting the state prevents the infinite loop of setting the state over and over. In my understanding, whenever you set the state (or change it), the DataGrid automatically re-renders itself and again re-setting the state hence the infinite loop.

I had the same problem. I used useRef to capture the change of sorting and after call it in the other part of the code.

const handleSort = (params: GridSortModel) => {
    const elem = params
    if (params && params.length) {
        sortRows.current = { field_order: `${elem[0].field}`, order: `${elem[0].sort}` }
    }
}
Related