Ag-Grid React Overview

Full working examples of ag-Grid and React can be found in Github, illustrating (amongst others) Rich Grids, Filtering with React Components Grid and so on.

ag-Grid React Features

Every feature of ag-Grid is available when using the ag-Grid React Component. The React Component wraps the functionality of ag-Grid, it doesn't duplicate, so there will be no difference between core ag-Grid and React ag-Grid when it comes to features.

Configuring the ag-Grid React Component

After importing AgGridReact you can then reference the component inside your JSX definitions. An example of the Grid Component can be seen below:

// Grid Definition <AgGridReact // listening for events onGridReady={this.onGridReady} // binding to array properties rowData={this.state.rowData} // no binding, just providing hard coded strings for the properties // boolean properties will default to true if provided (ie animateRows => animateRows="true") rowSelection="multiple" animateRows // setting grid wide date component dateComponentFramework={DateComponent} // setting default column properties defaultColDef={{ headerComponentFramework: SortableHeaderComponent, headerComponentParams: { menuIcon: 'fa-bars' } }}> // column definitions <AgGridColumn field="make"></AgGridColumn> </AgGridReact>>

Configuring the Columns

Columns can be defined in three ways: declaratively (i.e. via markup), via GridOptions or by binding to columnDefs on the AgGridReact component.

In all cases all column definition properties can be defined to make up a column definition.

Defining columns declaratively:

// column definitions <AgGridColumn field="make"></AgGridColumn> <AgGridColumn field="model"></AgGridColumn> <AgGridColumn field="price"></AgGridColumn>

Defining columns via GridOptions:

// before render/grid initialisation this.state = { gridOptions = { columnDefs: [ {make: "Toyota", model: "Celica", price: 35000}, {make: "Ford", model: "Mondeo", price: 32000}, {make: "Porsche", model: "Boxter", price: 72000} ] } } // in the render method <AgGridReact gridOptions={this.state.gridOptions}></AgGridReact>

Defining columns by binding to a property:

// before render/grid initialisation this.state = { columnDefs: [ {make: "Toyota", model: "Celica", price: 35000}, {make: "Ford", model: "Mondeo", price: 32000}, {make: "Porsche", model: "Boxter", price: 72000} ] } // in the render method <AgGridReact columnDefs={this.state.columnDefs}></AgGridReact>

Column definitions via markup or on GridOptions are one-off definitions. Subsequent updates will not be reflected on the Grid. Updates using property binding will be reflected on the Grid.

A full working Grid definition is shown below, illustrating various Grid & Column property definitions:

<AgGridReact // listening for events onGridReady={this.onGridReady} // binding to array properties rowData={this.state.rowData} // no binding, just providing hard coded strings for the properties // boolean properties will default to true if provided (ie animateRows => animateRows="true") rowSelection="multiple" animateRows // setting grid wide date component dateComponentFramework={DateComponent} // setting default column properties defaultColDef={{ sortable: true, filter: true, headerComponentFramework: SortableHeaderComponent, headerComponentParams: { menuIcon: 'fa-bars' } }}> <AgGridColumn headerName="#" width={30} checkboxSelection suppressMenu pinned></AgGridColumn> <AgGridColumn headerName="Employee" headerGroupComponentFramework={HeaderGroupComponent}> <AgGridColumn field="name" width={150} pinned editable cellEditorFramework={NameCellEditor}></AgGridColumn> <AgGridColumn field="country" width={150} pinned editable cellRenderer={RichGridDeclarativeExample.countryCellRenderer} filterParams={{cellRenderer: RichGridDeclarativeExample.countryCellRenderer, cellHeight:20}}></AgGridColumn> </AgGridColumn> </AgGridReact>

Loading CSS

You need 1) the core ag-Grid css and 2) a theme. These are stored in css files packaged in the core ag-Grid. To access them, first up we need to define an alias to use inside webpack.config.js: resolve: { alias: { "ag-grid-community": path.resolve('./node_modules/ag-grid-community') Once this is done, we can then access the two css files that we need as follows: import 'ag-grid-community/dist/styles/ag-grid.css'; import 'ag-grid-community/dist/styles/ag-theme-balham.css'; You will also need to configure CSS loaders for Webpack - you can find a full working example of this in our React Examples Repo on Github.

Applying a Theme

You need to set a theme for the grid. You do this by giving the grid a CSS class, one of ag-theme-balham, ag-theme-material, ag-theme-fresh, ag-theme-blue or ag-theme-dark. You must have the CSS loaded as specified above for this to work.

// a parent container of the grid, you could put this on your body tag // if you only every wanted to use one style of grid // HTML <div class="ag-theme-balham"> ... // OR JSX <div className="ag-theme-balham"> ... // then later, use the grid <AgGridReact ...

Grid API

When the grid is initialised, it will fire the gridReady event. If you want to use the API of the grid, you should put an onGridReady(params) callback onto the grid and grab the api from the params. You can then call this api at a later stage to interact with the grid (on top of the interaction that can be done by setting and changing the props).

// provide gridReady callback to the grid <AgGridReact onGridReady={this.onGridReady} .../> // in onGridReady, store the api for later use onGridReady = (params) => { this.api = params.api; this.columnApi = params.columnApi; } // use the api some point later! somePointLater() { this.api.selectAll(); this.columnApi.setColumnVisible('country', visible); }

The api and columnApi are also stored inside the React backing object of the grid. So you can also look up the backing object via React and access the api and columnApi that way.

Now would be a good time to try it in a simple app and get some data displaying and practice with some of the grid settings before moving onto the advanced features of cellRendering and custom filtering.

Cell Rendering, Cell Editing and Filtering using React

It is possible to build cell renderers, cell editors and filters using React. Doing each of these is explained in the section on each.

Override React Components Container Style

When you provide a React Component to ag-Grid for use within the grid it will create a div for the component to live in. If you wish to override the style of this div you can do so via the reactContainer property made available via props:

constructor(props) { super(props); // change the containing div to be inline-block (instead of the default block for a div) this.props.reactContainer.style.display = "inline-block"; // change the background color of the containing div to be red this.props.reactContainer.style.backgroundColor = "red"; }

You can see an example of this in the Grouped Row Example where we change the display of the groupRowInnerRendererFramework to inline-block so that the +/- and label are inline.

Performance Pitfalls

If you find that ag-Grid is re-rendering everything and you're not expecting this, then you're probably changing a property unexpectedly - below we document some common pitfalls that are easily avoided:

  • Binding to methods in the React binding
  • Changing references to colDefs (even if the contents are the same)
  • Changing references to rowData (even if the contents are the same)
  • Processing data before passing it down to ag-Grid

Binding to methods in the React binding

If you have something like:

<AgGridReact // events onGridReady={this.onGridReady.bind(this)}> //... rest of the configuration

Then everytime the component renders, a new instance of onGridReady will be passed to ag-Grid and it will believe that it's a different function. To avoid this, do the binding separately (in the constructor for example):

class TopMoversGrid extends Component { constructor(props) { super(props); // grid events this.onGridReady = this.onGridReady.bind(this); } render() { return ( <div className="ag-theme-balham"> <AgGridReact // events onGridReady={this.onGridReady}> //... rest of the component

Now ag-Grid will get the same function everytime the component renders.

Changing references to colDefs (even if the contents are the same)

This happens most commonly when using redux - even if the actual colDefs aren't changing, ag-Grid gets a new reference to each time there are changes, which causes a change cycle to occur.

To alleviate this extract the colDefs from the changing state (i.e. if the columns aren't likely to change extract them into a component variable, and pass this to ag-Grid).

Changing references to rowData (even if the contents are the same)

As above, you can either extract this rowData into a separate variable if the data isn't actually changing, or make use of the enableImmutableMode above.

Processing data before passing it down to ag-Grid

Similar to the items above, processing data and then passing this to ag-Grid, even if the resulting data hasn't changes, can result is ag-Grid changing state.

A common scenario might be where you pre-process your row data before passing it to ag-Grid - for example:

class TopMoversGrid extends Component { constructor(props) { super(props); } cleanData = () => { return this.props.rowData.filter(data => data.isClean) } render() { return ( <AgGridReact rowData={this.cleanData()} // ...rest of the component

As above, this call will result in ag-Grid believing that the rowData has changed each time the component renders as the filtering operation will return a new array each time. Again to alleviate this behaviour extract data that isn't likely to change and pre-process it only once.

React Portals

Within ag-Grid we make use of ReactDOM.unstable_renderSubtreeIntoContainer to dynamically generate React components within the grid.

This has worked well and been reliable since ag-Grid was created, but it is marked as unstable and so could be removed by the React team at any time.

With React 16 Portals were introduced and these are the preferred way to create React components dynamically.

If you wish to try use this feature you'll need to enable it as follows:

// Grid Definition <AgGridReact reactNext={true} ...other bindings

React Portals with Redux

One of the downsides of using the React Portal functionality is that there are a few more steps required for the newly created React components to be Redux aware.

Make the Store Available to ag-Grid

When using React Portals we need to explicity suplly the store to the dynamically created component. In order to be able to do this you in turn need to supply the store to ag-Grid React via the React context:

// Grid Definition <AgGridReact reactNext={true} reduxStore={this.context.store} // must be supplied when using redux with reactNext ...other bindings

To ensure the store is available on the context you need to add it to the parent component contextTypes:

GridComponent.contextTypes = { store: PropTypes.object };

Higher Order Components

If you use connect to use Redux, or if you're using a Higher Order Component to wrap the React component at all, you'll also need to ensure the grid can get access to the newly created component. To do this you need to ensure withRef is set:

export default connect( (state) => { return { currencySymbol: state.currencySymbol, exchangeRate: state.exchangeRate } }, null, null, { forwardRef: true } // must be supplied for react/redux when using GridOptions.reactNext )(PriceRenderer);

React Context API

If you're using the new React Context API then you can access the context in the components used within the grid.

First, let's create a context we can use in our components:

import React from "react"; export default React.createContext('normal');

Next we need to provide the context in a parent component (at the Grid level, or above) - for example:

<FontContext.Provider value="bold"> <GridComponent/> </FontContext.Provider>

Finally, we need to consume the context within our component:

class StyledRenderer extends Component { render() { return ( <FontContext.Consumer> {fontWeight => <span style={{fontWeight}}>Stylised Component!</span> } </FontContext.Consumer> ); } }

Working Example

You can find a fully working example at our ag Grid React Example. The Simple Redux Example makes use of reactNext together with Redux.


Test our React Grid component



Next Steps

Now you can go to reference to learn about accessing all the features of the grid.