reactjsag-gridag-grid-react

Preventing AgGrid From Re-Rendering When Navigate Away and Come Back in React


Problem I am using AgGrid in my React application. I have multiple pages each with their own grid. I want to be able to navigate between the various pages but have the state (filters, sort, column order, etc) of the AgGrid retained when I return to a page.

What is Currently Happening Currently, what happens is that when I leave a page (using react-router-dom) and then return to it the AgGrid will render again from scratch, which results in the loss of all of the filtering and column configuration which had been performed before leaving the page. My ideal outcome is for it to be preserved so that when I navigate away from it and then return it is loaded instantaneously (because it doesn’t need to render again) and with the same configuration as the user has left it.

What I have tried I thought that I should be able to do this by lifting the AgGrid up to a parent component, similar to what you may do with a input field if you wanted it to be preserved between page changes, but it still resets every time I navigate away and come back. In the below example I should be able to move between path1 and path2 and preserve the grid on each respective page.

Other parameters I don't want to do this using getColumnState / applyColumnState because it results in a lag on load, I'd ideally like to preserve the state so it does not need to re-render at all. Additionally, when a user refreshes the entire website I would like these tables to be reset to default.

Step 1: Created a generic table component

MasterTable.js

import React, { useEffect, useState, useRef, useMemo } from "react";
import { AgGridReact } from "ag-grid-react";
import "../components/tables/ag-grid-theme-builder.css";

export default function MasterTable({ columns, rowData }) {
    const gridRef = useRef();
  
    return (
        <div className="ag-theme-alpine flex-grow">
            <AgGridReact
                className="ag-theme-custom h-full"
                ref={gridRef}
                rowData={rowData}
                columnDefs={columns}
                sideBar={{
                    toolPanels: [
                        {
                            id: "filters",
                            labelDefault: "Filters",
                            labelKey: "filters",
                            iconKey: "filter",
                            toolPanel: "agFiltersToolPanel",
                        },
                        {
                            id: "columns",
                            labelDefault: "Columns",
                            labelKey: "columns",
                            iconKey: "columns",
                            toolPanel: "agColumnsToolPanel",
                            toolPanelParams: {
                                suppressRowGroups: true,
                                suppressValues: true,
                            },
                        },
                    ],
                }}
            />
        </div>
    );
}

Step 2: Create Table in Variable and Pass to Componentss

App.js

import React, { useState, useEffect, useRef } from "react";
import { BrowserRouter, Routes, Route, Navigate, Link } from "react-router-dom";
import Component

function App() {


   const [rowData1, setRowData1] = useState([dummyRowData1]);
   const [rowData2, setRowData2] = useState([dummyRowData2]);
   const [colDefs1, setColDefs1] = useState([dummyColData1]);
   const [colDefs2, setColDefs2] = useState([dummyColData2]);

 
   const table1 = (
        <MasterTable columns={colDefs1} rowData={rowData1} columnState= />
   );

   const table2 = (
        <MasterTable columns={colDefs2} rowData={rowData2} columnState= />
   );

   return (
      <>

      <Routes>
         <Route
            path="/path1/"
            element={<Component key="path1" table={table1}/>}
         />
         <Route
            path="/path2/"
            element={<Component key="path2" table={table2}/>}
         />
      </Routes>
      </>
   )
}

Step 3: Display Table in Component

Component.js

export default function Component({table}) {
   return (
      <>
          {table}
      </>
   )
}

Solution

  • You can use the AgGridReact table component's onStateUpdated callback prop to save the current table state, e.g. it's column sort order and filtering criteria, etc, into a React state, to be passed back to each table's initialState prop when the table remounts/rerenders after route changes.

    Example:

    App

    // Import ag-Grid styles
    import "ag-grid-community/styles/ag-grid.css"; // Core grid CSS
    import "ag-grid-community/styles/ag-theme-alpine.css"; // Alpine theme CSS
    
    import React from "react";
    import { BrowserRouter, Routes, Route, Navigate } from "react-router-dom";
    import { AgGridReact } from "ag-grid-react";
    
    import { rowData1, rowData2, colDefs1, colDefs2 } from "./TableData.js";
    import TablePage from "./TablePage";
    
    export default function App() {
      const [tableState, setTableState] = React.useState({
        table1: undefined,
        table2: undefined,
      });
    
      const onTableStateUpdated =
        (tableId) =>
        ({ state }) => {
          setTableState((tableState) => ({
            ...tableState,
            [tableId]: state,
          }));
        };
    
      const table1 = (
        <AgGridReact
          key="table1"
          rowData={rowData1}
          columnDefs={colDefs1}
          initialState={tableState.table1}
          onStateUpdated={onTableStateUpdated("table1")}
        />
      );
    
      const table2 = (
        <AgGridReact
          key="table2"
          rowData={rowData2}
          columnDefs={colDefs2}
          initialState={tableState.table2}
          onStateUpdated={onTableStateUpdated("table2")}
        />
      );
    
      return (
        <BrowserRouter>
          <Routes>
            <Route path="/" element={<Navigate to="/path1" replace />} />
            <Route
              path="/path1"
              element={<TablePage title="Title 1">{table1}</TablePage>}
            />
            <Route
              path="/path2"
              element={<TablePage title="Title 2">{table2}</TablePage>}
            />
          </Routes>
        </BrowserRouter>
      );
    }
    

    TablePage

    import React from "react";
    import { Link, useLocation } from "react-router-dom";
    
    export default function TablePage({ title, children }) {
      const { pathname } = useLocation(); // Get the current location (path)
    
      // Conditionally set the link to the opposite path
      const oppositePath = pathname === "/path1" ? "/path2" : "/path1";
      const linkText = pathname === "/path1" ? "Go to Path 2" : "Go to Path 1";
    
      return (
        <>
          <h1>{title}</h1>
          <div className="ag-theme-alpine" style={{ height: 400, width: "100%" }}>
            {children}
          </div>
          <Link to={oppositePath}>{linkText}</Link>
        </>
      );
    }
    

    Demo

    Edit preventing-aggrid-from-re-rendering-when-navigate-away-and-come-back-in-react