mj_
mj_

Reputation: 6447

MaterialUI Data-Grid Loading Animation Infinite Loop

I am using Material-UI Data-Grid, and I'm running a tutorial grid for server-side data access. This is written in React, and I'm having a problem that the loading circle is permanently spinning. I set a breakpoint in React.useEffect and I see it getting hit over and over and over. handlePageChange doesn't seem to be participating in the infinite loop.

Thinking about this a little, I feel that the state is changing which triggers the whole thing to execute again, hence the loop. What is the condition supposed to be to stop the thing?

import * as React from 'react';
import { DataGrid } from '@material-ui/data-grid';

function loadServerRows(page, data) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(data.rows.slice(page * 5, (page + 1) * 5));
    }, Math.random() * 500 + 100); // simulate network latency
  });
}

export default function App() {

  const data = {
    rows: [
      { id: 1, col1: 'Hello', col2: 'World' },
      { id: 2, col1: 'XGrid', col2: 'is Awesome' },
      { id: 3, col1: 'Material-UI', col2: 'is Amazing' },
    ],
    columns: [
      { field: 'col1', headerName: 'Column 1', width: 150 },
      { field: 'col2', headerName: 'Column 2', width: 150 },
    ],
    rowLength: 100,
    maxColumns: 6
  }

  const [page, setPage] = React.useState(0);
  const [rows, setRows] = React.useState([]);
  const [loading, setLoading] = React.useState(false);

  const handlePageChange = (params) => {
    setPage(params.page);
  };

  React.useEffect(() => {
    let active = true;

    (async () => {
      setLoading(true);
      const newRows = await loadServerRows(page, data);

      if (!active) {
        return;
      }

      setRows(newRows);
      setLoading(false);
    })();

    return () => {
      active = false;
    };
  }, [page, data]);

  return (
    <div style={{ height: 400, width: '100%' }}>
      <DataGrid
        rows={rows}
        columns={data.columns}
        pagination
        pageSize={5}
        rowCount={100}
        paginationMode="server"
        onPageChange={handlePageChange}
        loading={loading}
      />
    </div>
  );
}

Upvotes: 3

Views: 17156

Answers (1)

Spatz
Spatz

Reputation: 20118

In your code data changes on each render. As an option, you can store data with useRef (or just make it global moving out of component):

import React from 'react'
import { DataGrid } from '@material-ui/data-grid'


function loadServerRows(page, data) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(data.rows.slice(page * 5, (page + 1) * 5))
    }, Math.random() * 500 + 100) // simulate network latency
  })
}

function App() {
  const data = React.useRef({
    rows: [
      { id: 1, col1: 'Hello', col2: 'World' },
      { id: 2, col1: 'XGrid', col2: 'is Awesome' },
      { id: 3, col1: 'Material-UI', col2: 'is Amazing' },
    ],
    columns: [
      { field: 'col1', headerName: 'Column 1', width: 150 },
      { field: 'col2', headerName: 'Column 2', width: 150 },
    ],
    rowLength: 100,
    maxColumns: 6
  })
  const [page, setPage] = React.useState(0)
  const [rows, setRows] = React.useState([])
  const [loading, setLoading] = React.useState(false)

  const handlePageChange = (params) => {
    setPage(params.page)
  }

  React.useEffect(() => {
    let active = true;

    (async () => {
      setLoading(true)
      const newRows = await loadServerRows(page, data.current)

      if (!active) {
        return
      }

      setRows(newRows)
      setLoading(false)
    })()

    return () => {
      active = false
    }
  }, [page, data])

  return (
    <div style={{ height: 400, width: '100%' }}>
      <DataGrid
        rows={rows}
        columns={data.current.columns}
        pagination
        pageSize={5}
        rowCount={100}
        paginationMode="server"
        onPageChange={handlePageChange}
        loading={loading}
      />
    </div>
  )
} 

Upvotes: 5

Related Questions