Material react table rendering performance issues

434 Views Asked by At

Use case: Render 5 material react tables under 5 different tabs.

My tech stack:

  • "material-react-table": "^2.0.4"
  • "@mui/material": "^5.14.13"
  • "@chakra-ui/react": "^2.4.2"
  • "@emotion/react": "^11.11.1"
  • "@emotion/styled": "^11.11.0"

Issue: Whenever I change my tab, there seems to be some slowness/lag on UI, and on the console, there seem to be some violations of 500 ms.

Console

I used the Chrome dev tools performance profiler to check what is taking time I drilled down to this: Chrome performance profiler

enter image description here

I suspect that the styles for my material react table are getting rendered again and again when I switch tabs which is causing this violation.

Psuedo code:

<MainComponent>
  <Tabs>
    <TabList>
      <Tab>Table1</Tab>
      <Tab>Table2</Tab>
      <Tab>Table3</Tab>
      <Tab>Table4</Tab>
    </TabList>
    <TabPanels>
      <TabPanel>
        <ThemeProvider theme={defaultMaterialTheme}>
          <MaterialReactTable table={table1} />
      </TabPanel>
      <TabPanel>
        <ThemeProvider theme={defaultMaterialTheme}>
          <MaterialReactTable table={table2} />
      </TabPanel>
      <TabPanel>
        <ThemeProvider theme={defaultMaterialTheme}>
          <MaterialReactTable table={table3} />
      </TabPanel>
      <TabPanel>
        <ThemeProvider theme={defaultMaterialTheme}>
          <MaterialReactTable table={table4} />
      </TabPanel>
    </TabPanel>
  </Tabs>
</MainComponent>

I understand that I should wrap up tabs under one ThemeProvider only. But that starts breaking the chakra UI CSS. Appreciate any help on this.

2

There are 2 best solutions below

1
Mhmdnzr On

about performance i can said somethings i implmented on my last project and improve 20 percent performance score in lighthouse:

  • don't put head table and content in rows in a table component, saparate head and user lazy loading for rows
  • use memo() internal fn react to cache table previous rendered items to prevent rerender again if rows didn't changes
  • additional you can use js-coockies (if your table is too large i don't suggest this item)

When using multiple UI libraries that apply styles globally, like Chakra UI and Material-UI, you might encounter conflicts between their styles. To resolve this, you can use a strategy that helps isolate the styles of each library.

Here are a few approaches you can consider:

Approach 1: Use ThemeProvider for Both Libraries

import { ThemeProvider as ChakraThemeProvider, CSSReset } from '@chakra-ui/react';
import { ThemeProvider as MuiThemeProvider } from '@mui/material/styles';

const MainComponent = () => {
  return (
    <ChakraThemeProvider>
      <CSSReset />
      <MuiThemeProvider theme={yourMuiTheme}>
        {/* Your MainComponent code */}
      </MuiThemeProvider>
    </ChakraThemeProvider>
  );
};

export default MainComponent;

This approach allows you to have separate ThemeProviders for Chakra UI and Material-UI, ensuring that each library's styles are applied in isolation.

Approach 2: Use Component-Level Styling

Apply the Chakra UI styles directly to the Chakra UI components within your MainComponent:

import { Box } from '@chakra-ui/react';

const MainComponent = () => {
  return (
    <Box>
      {/* Chakra UI components here */}
      <MuiThemeProvider theme={yourMuiTheme}>
        {/* Material-UI components here */}
      </MuiThemeProvider>
    </Box>
  );
};

export default MainComponent;

This approach keeps the styles for each library within their respective components.

Approach 3: Use Class Prefixing

Some libraries allow you to customize the prefix for generated CSS classes. This way, you can prefix Chakra UI styles with a specific class, and Material-UI styles with another.

Example using Chakra UI with custom class prefix:

import { ChakraProvider, CSSReset } from '@chakra-ui/react';

const MainComponent = () => {
  return (
    <ChakraProvider className="chakra">
      <CSSReset />
      <MuiThemeProvider theme={yourMuiTheme}>
        {/* Your MainComponent code */}
      </MuiThemeProvider>
    </ChakraProvider>
  );
};

export default MainComponent;

In this example, Chakra UI styles will be scoped under the class chakra.

Approach 4: Use a Custom Styles Container

If none of the above solutions work, consider creating a custom container for one of the libraries. This container can encapsulate all the components of that library and be styled separately.

// CustomMaterialContainer.js
import { ThemeProvider } from '@mui/material/styles';

const CustomMaterialContainer = ({ children }) => {
  return (
    <ThemeProvider theme={yourMuiTheme}>
      {children}
    </ThemeProvider>
  );
};

export default CustomMaterialContainer;

In your MainComponent:

import { ChakraProvider, CSSReset } from '@chakra-ui/react';
import CustomMaterialContainer from './CustomMaterialContainer';

const MainComponent = () => {
  return (
    <ChakraProvider>
      <CSSReset />
      <CustomMaterialContainer>
        {/* Your MainComponent code */}
      </CustomMaterialContainer>
    </ChakraProvider>
  );
};

export default MainComponent;

Choose the approach that best fits your use case and integrates well with the structure of your application. Experiment with these solutions and see which one resolves the styling conflicts in the most satisfactory way for your specific requirements.

0
Shikhar Thapliyal On

I solved the UI lag and violation issue. Turns out my table1 and table2 components were getting re-rendered because its columns and data were getting recomputed due to dependency of a state. Also i learnt that, passing a function result Array.filter as a prop to a component is a dangerous thing to do as it keeps changing the reference, hence the recompilation and re rendering.