Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / React

Utilize useState or useRef Hooks and gridReady Event to Maintain Access to Grid API and Column API

5.00/5 (1 vote)
3 Mar 2020CPOL3 min read 19.2K  
ag-Grid API Access with Hooks
This post provides code samples and shows how to utilize useState or useRef hooks and gridReady event to maintain access to Grid API and Column API. You will also be able to see a demo of useRef vs, useState and discusses the difference between the two versions.

Check here for code samples.

AG-GRID IN REACT 16.8.0+

ag-Grid has an impressive set of features, matched by unusually comprehensive documentation. The issue is that at this moment (February 2020), most of the React-specific examples are written for class components. Because of this, using the grid inside a function (functional) component could be slightly challenging. One of the things that are not so obvious is how to access Grid API and Column API...

Grid and Column APIs have over 150 methods that let you manipulate everything from cell focus to column width. The docs suggest obtaining and saving references to these APIs inside gridReady event handler:

JavaScript
class GridExample extends Component {
  // Irrelevant parts removed for brevity... 

  onGridReady = params => {
    this.gridApi = params.api;
    this.gridColumnApi = params.columnApi;
  }

  render() {
    return (
		<AgGridReact          
            onGridReady={this.onGridReady}            
        />  
    );
  }	
}

Such approach works nicely in a class component but doesn't work when component is "just" a function. Worry not! useState and useRef hooks (part of React 16.8.0) can help you access the APIs in a function component and it's all quite easy!

I've asked ag-Grid team if they have a preference between useState and useRef and they don't, so I will show you the two options and you can pick the one that suits you.

Here's a component that uses selectAll method from Grid API and moveColumnByIndex method from Column API with the help of useState hook:

JavaScript
import React, { useState } from "react";
import { AgGridReact } from "ag-grid-react";

import { columnDefs } from "./columnDefs";
import { rowData } from "./rowData";

import "ag-grid-community/dist/styles/ag-grid.css";
import "ag-grid-community/dist/styles/ag-theme-balham.css";

const AgGridWithUseState = () => {
  console.log("AgGridWithUseState Render");

  const [gridApi, setGridApi] = useState();
  const [columnApi, setColumnApi] = useState();

  return (
    <div className="example">
      <h1>API access with useState</h1>
      <div>
        <button
          onClick={() => gridApi && gridApi.selectAll()}>
          Grid API selectAll()
        </button>
        <button 
          onClick={() => columnApi && columnApi.moveColumnByIndex(0, 1)}>
          Column API moveColumnByIndex(0, 1)
        </button>
      </div>
      <div className="ag-theme-balham">
        <AgGridReact
          columnDefs={columnDefs}
          rowData={rowData}
          rowSelection="multiple"
          onGridReady={params => {
            console.log("AgGridWithUseState Grid Ready");
            setGridApi(params.api);
            setColumnApi(params.columnApi);
          }}
        />
      </div>
    </div>
  );
};

export default AgGridWithUseState;

and below is the exact same thing done with useRef:

JavaScript
import React, { useRef } from "react";
import { AgGridReact } from "ag-grid-react";

import { columnDefs } from "./columnDefs";
import { rowData } from "./rowData";

import "ag-grid-community/dist/styles/ag-grid.css";
import "ag-grid-community/dist/styles/ag-theme-balham.css";

const AgGridWithUseRef = () => {
  console.log("AgGridWithUseRef Render");

  const gridApi = useRef();
  const columnApi = useRef();

  return (
    <div className="example">
      <h1>API access with useRef</h1>
      <div>
        <button
          onClick={() => gridApi.current && gridApi.current.selectAll()}>
          Grid API selectAll()
        </button>
        <button
          onClick={() => columnApi.current && columnApi.current.moveColumnByIndex(0, 1)}>
          Column API moveColumnByIndex(0, 1)
        </button>
      </div>
      <div className="ag-theme-balham">
        <AgGridReact
          columnDefs={columnDefs}
          rowData={rowData}
          rowSelection="multiple"
          onGridReady={params => {
            console.log("AgGridWithUseRef Grid Ready");
            gridApi.current = params.api;
            columnApi.current = params.columnApi;
          }}
        />
      </div>
    </div>
  );
};

export default AgGridWithUseRef;

Check the function assigned to onGridReady property to find out how to retrieve and keep references to the APIs. Button's onClick handlers show you how to use the APIs.

USEREF VS USESTATE (DEMO)

The app uses React 16.12.0 and ag-Grid Community 22.1.1 (I've tested it in Chrome 80, Firefox 73, Edge 44).
Clone the repo, do npm install and npm start to run the app locally (just like with any other thing started with create-react-app)...

The demo shows access to selectAll method from Grid API and moveColumnByIndex method from Column API. This application has two grids that differ only in the way the APIs are accessed (one uses useState hook, the other goes with useRef hook).

What's the Difference between useState and useRef Version?

It boils down to the way hooks are designed to work. useState causes component rerender and useRef doesn't. You can see the difference if you open the console and check the log:

useState vs useRef - render calls

Notice two "AgGridWithUseState Render" lines after "AgGridWithUseState Grid Ready".

This happens because Grid and Column APIs are set by two calls to state hook setters and that causes component rerenders. Sounds bad? Remember that in React, a component rerender doesn't necessary mean any DOM change has to be applied. ag-Grid is also smart enough to avoid unnecessary work. useState triggers rendering by design and it lets you write the component in a more declarative way. For example, you could keep rowData and columnDefs in state and have the grid update itself without explicit API calls...

How about the useRef approach? Use it if you don't need to run any action as a result of API reference being set.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)