6

What is the best way of accessing ag-Grid API inside of React function component?

I have to use some of the methods from API (getSelectedNodes, setColumnDefs etc.) so I save a reference to the API (using useState hook) in onGridReady event handler:

onGridReady={params => {
    setGridApi(params.api);
}}

and then I can call the API like this: gridApi.getSelectedNodes()

I haven't noticed any problems with this approach, but I'm wondering if there's more idiomatic way?

Stack:

  • ag-grid-community & ag-grid-react 22.1.1
  • react 16.12.0
user1068352
  • 534
  • 6
  • 14

4 Answers4

9

We find the most idiomatic way to use a ref. As the api is not a state of our component. It is actually possible to simply do:

<AgGridReact ref={grid}/>

and then use it with

grid.current.api

Here an example:

import React, { useRef } from 'react'
import { AgGridReact } from 'ag-grid-react'
import { AgGridReact as AgGridReactType } from 'ag-grid-react/lib/agGridReact'

const ShopList = () => {
  const grid = useRef<AgGridReactType>(null)

 ...

  return (
    <AgGridReact ref={grid} columnDefs={columnDefs} rowData={shops} />
  )

}

The good thing here is, that you will have access to the gridApi but als to to the columnApi. Simply like this:

// rendering menu to show/hide columns:
{columnDefs.map(columnDef =>
  <>
    <input
    type='checkbox'
    checked={
        grid.current
        ? grid.current.columnApi.getColumn(columnDef.field).isVisible()
        : !(columnDef as { hide: boolean }).hide
    }
    onChange={() => {
        if (grid.current?.api) {
        const col = grid.current.columnApi.getColumn(columnDef.field)
        grid.current.columnApi.setColumnVisible(columnDef.field, !col.isVisible())
        grid.current.api.sizeColumnsToFit()
        setForceUpdate(x => ++x)
        }
    }}
    />
    <span>{columnDef.headerName}</span>
  </>
)}
pa1nd
  • 253
  • 2
  • 11
  • This should be the new accepted answer. Best in line with the official docs. – BitShift Jun 03 '20 at 07:58
  • As a suggestion, you may want to add `// prettier-ignore` above the `const grid = useRef(null)` line to prevent prettier auto-formatting it in VS Code. – waqasahmed Feb 13 '21 at 23:51
7

Well I am doing it in my project. You can use useRef hook to store gridApi.

const gridApi = useRef();

const onGridReady = params => {

   gridApi.current = params.api;  // <== this is how you save it

   const datasource = getServerDataSource(
     gridApi.current,
     {
       size: AppConstants.PAGE_SIZE,
       url: baseUrl,
       defaultFilter: props.defaultFilter
     }
   );

  gridApi.current.setServerSideDatasource(datasource); // <== this is how you use it
};
Sushmit Sagar
  • 1,078
  • 1
  • 8
  • 21
  • This seems like viable option too! I wish somebody from ag-Grid team observed ag-grid tag on SE and provide authoritative answer... :/ – user1068352 Feb 14 '20 at 11:45
  • @user1068352 yeah me too. I also have couple of questions for functional component agGrid on my SE account. I request you kindly upvote and accept the answer if it helped you :) – Sushmit Sagar Feb 14 '20 at 11:49
  • I will try to reach ag team to get an official recommendation. If it matches with useRef I'll definitely accept your answer. Remember to upvote a question ;) – user1068352 Feb 14 '20 at 14:39
0

I'm running into the same issue but here is a workaround that at least can get you the selected rows. Essentially what I'm doing is sending the api from the agGrid callbacks to another function. Specifically I use OnSelectionChanged callback to grab the current row node. Example below:

  const onSelectionChanged = params => {
    setDetails(params.api.getSelectedRows());
  };

return (<AgGridReact
          columnDefs={agData.columnDefs}
          rowSelection={'single'}
          enableCellTextSelection={true}
          defaultColDef={{
            resizable: true,
          }}
          rowHeight={50}
          rowData={agData.rowData}
          onCellFocused={function(params) {
            if (params.rowIndex != null) {
              let nNode = params.api.getDisplayedRowAtIndex(params.rowIndex);
              nNode.setSelected(true, true);
            }
          }}
          onSelectionChanged={function(params) {
            onSelectionChanged(params);
            params.api.sizeColumnsToFit();
          }}
          onGridReady={function(params) {
            let gridApi = params.api;
            gridApi.sizeColumnsToFit();
          }}
          deltaRowDataMode={true}
          getRowNodeId={function(data) {
            return data.id;
          }}
        />);
  • I would like to have persistent access to the API though - I even tried hooking the api to the component state but it seems to lose scope of the original grid instance...it seems to create new instances that are not associated with the initial grid API.. FYI I am using React Boilerplate with Redux, Sagas, Reselect, etc. – Jose R. Perez Feb 11 '20 at 18:10
  • Have you tried useState hook? It works for me just fine. – user1068352 Feb 11 '20 at 19:08
-1

Just wondering, why do you need to use state-hook, cuz gridApi wouldn't be changed during lifetime circle.

If you will check ag-grid team samples, you will see that they are using just property binding for it:

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

So I suppose, you don't need to use state for storing the API reference.

un.spike
  • 4,052
  • 2
  • 14
  • 31
  • Can you point me to the ag-grid team sample you mention that uses this.gridApi inside a function (functional) component (not a class based one)? – user1068352 Feb 10 '20 at 12:44
  • pick anything from documentation (and select ReactJS on combo-box) [just an example](https://www.ag-grid.com/javascript-grid-cell-editing/#example-cell-editing) – un.spike Feb 10 '20 at 15:55
  • These are class-based examples. My question is explicitly about function components. – user1068352 Feb 10 '20 at 19:07
  • Notice that all the examples are currently written with classes, like: `class GridExample extends Component {` – user1068352 Feb 11 '20 at 10:42
  • @user1068352 sorry didn't get the idea what you are looking for – un.spike Feb 11 '20 at 10:51