reactjstypescriptmaterial-uinext.jsreact-loading-skeleton

Adding skeleton effect to a table with sorting/pagination


I want to add Skeleton effect to a MUI table. The only requirement for the table is sorting and pagination features. I added loading hook and fake data fetching with 3 seconds delay in order to test, but it doesn't seem possible with DataGrid.

import { useState, useEffect } from 'react';
import type { NextPage } from 'next';
import Container from '@mui/material/Container';
import Box from '@mui/material/Box';
import { DataGrid, GridColDef } from '@mui/x-data-grid';
import { Paper } from '@mui/material';

const columns: GridColDef[] = [
  { field: 'id', headerName: 'ID' },
  { field: 'title', headerName: 'Title', width: 300 },
  { field: 'body', headerName: 'Body', width: 600 },
];

const Home: NextPage = () => {
  const [posts, setPosts] = useState([]);
  const [loading, setLoading] = useState(true);

  // fetch data from fake API
  useEffect(() => {
    setInterval(
      () =>
        fetch('https://jsonplaceholder.typicode.com/posts')
          .then((response) => response.json())
          .then((data) => {
            setPosts(data);
            setLoading(false);
          }),
      3000
    );
  }, []);

  return (
    <Container maxWidth="lg">
      <Box
        sx={{
          my: 4,
          display: 'flex',
          flexDirection: 'column',
          justifyContent: 'center',
          alignItems: 'center',
        }}
      >
        <Paper sx={{ width: '100%' }}>
          <DataGrid
            rows={posts}
            columns={columns}
            pageSize={10}
            autoHeight
            rowsPerPageOptions={[10]}
            disableSelectionOnClick
            disableColumnMenu
            disableColumnSelector
          />
        </Paper>
      </Box>
    </Container>
  );
};

export default Home;


Solution

  • Mui DataGrid have some custom options to use for loading which you can find at https://mui.com/components/data-grid/components/#loading-overlay , in all if you want to set a custom loading component your DataGrid component will look like

        // You can find a proper height for the Paper component (if you do that 
        // you will need to remove autoHeight from data grid) , or change the data grid height  . 
        // if not the table height wont fit and you will need to edit some styles .
    
         <Paper sx={{ width: "100%" , height: "600px" }}> 
               <DataGrid
                rows={posts}
                columns={columns}
                pageSize={10}
                // autoHeight
                // sx={{minHeight: 600}}  if you want to use autoHeight you will need add some height
                rowsPerPageOptions={[10]}
                disableSelectionOnClick
                disableColumnMenu
                disableColumnSelector
                components={{
                  LoadingOverlay: LoadingSkeleton  
                }}
                loading={loading}   // you need to set your boolean loading
              />
        </Paper>
    

    you can make your custom component with Skeleton

      const LoadingSkeleton = () => (
              <Skeleton variant="rectangular" sx={{ my: 4, mx: 1 }} />
     );
    

    also if you to make a list of rowing skeletons

    const LoadingSkeleton = () => (
      <Box
        sx={{
          height: "max-content"
        }}
      >
        {[...Array(10)].map((_) => (
          <Skeleton variant="rectangular" sx={{ my: 4, mx: 1 }} />
        ))}
      </Box>
    );
    

    a simple example can be found here https://codesandbox.io/s/trusting-rgb-wwqd2o?file=/src/App.js:440-644 , the list of rowing skeletons might needs some changes in styling .