Search results

Immutable Mode in React Grid component

23 Feb 2021 / 4 minutes to read

The immutable mode optimizes the Grid re-rendering performance by using the object reference and deep compare concept. When performing the Grid actions, it will only re-render the modified or newly added rows and prevent the re-rendering of the unchanged rows.

To enable this feature, you have to set the enableImmutableMode property as true.

  • This feature uses the primary key value for data comparison. So, you need to provide the isPrimaryKey column.
Source
Preview
App.tsx
datasource.tsx
import { ColumnDirective, ColumnsDirective, GridComponent, Inject, Page } from '@syncfusion/ej2-react-grids';
import { ButtonComponent } from '@syncfusion/ej2-react-buttons';
import * as React from 'react';
import { data } from './datasource';

export default class App extends React.Component<{}, {}>{
    public pageSettings: object = { pageSize: 50 };
    public immutableInit: boolean = true;
    public init: boolean = true;
    public primaryKey: number = 0;
    public normalStart: number;
    public immutableStart: number;
    public immutableGrid: GridComponent;
    public normalGrid: GridComponent;
    public topBtn: ButtonComponent;
    public bottomBtn: ButtonComponent;
    public deleteBtn: ButtonComponent;
    public sortBtn: ButtonComponent;
    public pageBtn: ButtonComponent;
     public immutableBeforeDataBound() {
        this.immutableStart = new Date().getTime();
    }
    public immutableDataBound() {
        let val: number | string = this.immutableInit ? '' : new Date().getTime() - this.immutableStart;
        document.getElementById("immutableDelete").innerHTML =
            "Immutable rendering Time: " + "<b>" + val + "</b>" + "<b>ms</b>";
        this.immutableStart = 0; this.immutableInit = false;
    }
    public addTopEvent() {
        let addedRecords: object[] = [
            { 'OrderID': ++this.primaryKey, 'ProductName': 'Chai', 'ProductID': 'Sasquatch Ale', 'CustomerID': 'QUEDE', 'CustomerName': 'Yoshi Tannamuri' },
            { 'OrderID': ++this.primaryKey, 'ProductName': 'Georg Pipps', 'ProductID': 'Valkoinen suklaa', 'CustomerID': 'RATTC', 'CustomerName': 'Martín Sommer' },
            { 'OrderID': ++this.primaryKey, 'ProductName': 'Yoshi Tannamuri', 'ProductID': 'Gula Malacca', 'CustomerID': 'COMMI', 'CustomerName': 'Ann Devon' },
            { 'OrderID': ++this.primaryKey, 'ProductName': 'Palle Ibsen', 'ProductID': 'Rogede sild', 'CustomerID': 'RATTC', 'CustomerName': 'Paula Wilson' },
            { 'OrderID': ++this.primaryKey, 'ProductName': 'Francisco Chang', 'ProductID': 'Mascarpone Fabioli', 'CustomerID': 'ROMEY', 'CustomerName': 'Jose Pavarotti' }
        ];
        let aData: object[] = addedRecords.concat(this.immutableGrid.dataSource as object[]);
        this.normalGrid.setProperties({ dataSource: aData });
        this.immutableGrid.setProperties({ dataSource: aData });
    }
    public addBottomEvent() {
        let addedRecords: object[] = [
            { 'OrderID': ++this.primaryKey, 'ProductName': 'Chai', 'ProductID': 'Sasquatch Ale', 'CustomerID': 'QUEDE', 'CustomerName': 'Yoshi Tannamuri' },
            { 'OrderID': ++this.primaryKey, 'ProductName': 'Georg Pipps', 'ProductID': 'Valkoinen suklaa', 'CustomerID': 'RATTC', 'CustomerName': 'Martín Sommer' },
            { 'OrderID': ++this.primaryKey, 'ProductName': 'Yoshi Tannamuri', 'ProductID': 'Gula Malacca', 'CustomerID': 'COMMI', 'CustomerName': 'Ann Devon' },
            { 'OrderID': ++this.primaryKey, 'ProductName': 'Palle Ibsen', 'ProductID': 'Rogede sild', 'CustomerID': 'RATTC', 'CustomerName': 'Paula Wilson' },
            { 'OrderID': ++this.primaryKey, 'ProductName': 'Francisco Chang', 'ProductID': 'Mascarpone Fabioli', 'CustomerID': 'ROMEY', 'CustomerName': 'Jose Pavarotti' }
        ]
        let aData: object[] = (this.immutableGrid.dataSource as object[]).concat(addedRecords);
        this.normalGrid.setProperties({ dataSource: aData });
        this.immutableGrid.setProperties({ dataSource: aData });
    }
    public deleteEvent() {
        (this.immutableGrid.dataSource as object[]).splice(0, 5);
        this.normalGrid.setProperties({ dataSource: this.immutableGrid.dataSource });
        this.immutableGrid.setProperties({ dataSource: this.immutableGrid.dataSource });
    }
    public sortEvent() {
        let aData: object[] = (this.immutableGrid.dataSource as object[]).reverse();
        this.normalGrid.setProperties({ dataSource: aData });
        this.immutableGrid.setProperties({ dataSource: aData });
    }
    public pageEvent() {
        let totalPage: number = (this.immutableGrid.dataSource as object[]).length / this.immutableGrid.pageSettings.pageSize;
        let page: number = Math.floor(Math.random() * totalPage) + 1;
        this.normalGrid.setProperties({ pageSettings: { currentPage: page } });
        this.immutableGrid.setProperties({ pageSettings: { currentPage: page } });
    }
    public beforeDataBound() {
        this.normalStart = new Date().getTime();
    }
    public dataBound() {
        let val: number | string = this.init ? '' : new Date().getTime() - this.normalStart;
        document.getElementById("normalDelete").innerHTML =
        "Normal rendering Time: " + "<b>" + val + "</b>" + "<b>ms</b>";
        this.normalStart = 0; this.init = false;
    }

    public render() {
    return (<div>
      <table>
          <tbody>
            <tr>
              <td>
                <span id="immutableDelete"></span>
              </td>
            </tr>
            <tr>
              <td>
                <span id="normalDelete"></span>
              </td>
            </tr>
            <tr>
              <td>
                <div>
                  <ButtonComponent ref={topInfo => { this.topBtn = topInfo }} cssClass='e-info' onClick={this.addTopEvent.bind(this)}>Add 5 rows at top</ButtonComponent>
                  <ButtonComponent ref={bottomInfo => { this.bottomBtn = bottomInfo }} cssClass='e-info' onClick={this.addBottomEvent.bind(this)}>Add 5 rows at bottom</ButtonComponent>
                  <ButtonComponent ref={deleteInfo => { this.deleteBtn = deleteInfo }} cssClass='e-info' onClick={this.deleteEvent.bind(this)}>Delete 5 rows</ButtonComponent>
                  <ButtonComponent ref={sortInfo => { this.sortBtn = sortInfo }} cssClass='e-info' onClick={this.sortEvent.bind(this)}>Sort Order ID</ButtonComponent>
                  <ButtonComponent ref={pageInfo => { this.pageBtn = pageInfo }} cssClass='e-info' onClick={this.pageEvent.bind(this)}>Paging</ButtonComponent>
                </div>
              </td>
            </tr>
            <tr>
              <td>
                <span><b>Immutable Grid</b></span>
                <GridComponent ref={immutable => { this.immutableGrid = immutable }} dataSource={data} height='250' enableImmutableMode={true} allowPaging={true} pageSettings={this.pageSettings} beforeDataBound={this.immutableBeforeDataBound.bind(this)} dataBound={this.immutableDataBound.bind(this)}>
                  <ColumnsDirective>
                    <ColumnDirective field='OrderID' headerText='Order ID' isPrimaryKey="true" width='120' textAlign='Right'></ColumnDirective>
                    <ColumnDirective field='ProductName' headerText='Product Name' width='160'></ColumnDirective>
                    <ColumnDirective field='ProductID' headerText='Product ID' width='130' textAlign='Right' />
                    <ColumnDirective field='CustomerID' headerText='Customer ID' width='120' />
                    <ColumnDirective field='CustomerName' headerText='Customer Name' width='160'></ColumnDirective>
                  </ColumnsDirective>
                   <Inject services={[Page]} />
                </GridComponent>
              </td>
            </tr>
            <tr>
              <td>
                <span><b>Normal Grid</b></span>
                <GridComponent ref={normal => { this.normalGrid = normal }} dataSource={data} height='250' allowPaging={true} pageSettings={this.pageSettings} beforeDataBound={this.beforeDataBound.bind(this)} dataBound={this.dataBound.bind(this)}>
                  <ColumnsDirective>
                    <ColumnDirective field='OrderID' headerText='Order ID' isPrimaryKey="true" width='120' textAlign='Right'></ColumnDirective>
                    <ColumnDirective field='ProductName' headerText='Product Name' width='160'></ColumnDirective>
                    <ColumnDirective field='ProductID' headerText='Product ID' width='130' textAlign='Right' />
                    <ColumnDirective field='CustomerID' headerText='Customer ID' width='120' />
                    <ColumnDirective field='CustomerName' headerText='Customer Name' width='160'></ColumnDirective>
                  </ColumnsDirective>
                   <Inject services={[Page]} />
                </GridComponent>
              </td>
            </tr>
          </tbody>
        </table></div>)
  }
};
export let data: Object[] = createLazyLoadData();

function createLazyLoadData() {
  let lazyLoadData: Object[] = [];
  let customerid: string[] = [
    "VINET",
    "TOMSP",
    "HANAR",
    "VICTE",
    "SUPRD",
    "HANAR",
    "CHOPS",
    "RICSU",
    "WELLI",
    "HILAA",
    "ERNSH",
    "CENTC",
    "OTTIK",
    "QUEDE",
    "RATTC",
    "ERNSH",
    "FOLKO",
    "BLONP",
    "WARTH",
    "FRANK",
    "GROSR",
    "WHITC",
    "WARTH",
    "SPLIR",
    "RATTC",
    "QUICK",
    "VINET",
    "MAGAA",
    "TORTU",
    "MORGK",
    "BERGS",
    "LEHMS",
    "BERGS",
    "ROMEY",
    "ROMEY",
    "LILAS",
    "LEHMS",
    "QUICK",
    "QUICK",
    "RICAR",
    "REGGC",
    "BSBEV",
    "COMMI",
    "QUEDE",
    "TRADH",
    "TORTU",
    "RATTC",
    "VINET",
    "LILAS",
    "BLONP",
    "HUNGO",
    "RICAR",
    "MAGAA",
    "WANDK",
    "SUPRD",
    "GODOS",
    "TORTU",
    "OLDWO",
    "ROMEY",
    "LONEP",
    "ANATR",
    "HUNGO",
    "THEBI",
    "DUMON",
    "WANDK",
    "QUICK",
    "RATTC",
    "ISLAT",
    "RATTC",
    "LONEP",
    "ISLAT",
    "TORTU",
    "WARTH",
    "ISLAT",
    "PERIC",
    "KOENE",
    "SAVEA",
    "KOENE",
    "BOLID",
    "FOLKO",
    "FURIB",
    "SPLIR",
    "LILAS",
    "BONAP",
    "MEREP",
    "WARTH",
    "VICTE",
    "HUNGO",
    "PRINI",
    "FRANK",
    "OLDWO",
    "MEREP",
    "BONAP",
    "SIMOB",
    "FRANK",
    "LEHMS",
    "WHITC",
    "QUICK",
    "RATTC",
    "FAMIA"
  ];

  let product: string[] = [
    "Chai",
    "Chang",
    "Aniseed Syrup",
    "Chef Anton's Cajun Seasoning",
    "Chef Anton's Gumbo Mix",
    "Grandma's Boysenberry Spread",
    "Uncle Bob's Organic Dried Pears",
    "Northwoods Cranberry Sauce",
    "Mishi Kobe Niku",
    "Ikura",
    "Queso Cabrales",
    "Queso Manchego La Pastora",
    "Konbu",
    "Tofu",
    "Genen Shouyu",
    "Pavlova",
    "Alice Mutton",
    "Carnarvon Tigers",
    "Teatime Chocolate Biscuits",
    "Sir Rodney's Marmalade",
    "Sir Rodney's Scones",
    "Gustaf's Knäckebröd",
    "Tunnbröd",
    "Guaraná Fantástica",
    "NuNuCa Nuß-Nougat-Creme",
    "Gumbär Gummibärchen",
    "Schoggi Schokolade",
    "Rössle Sauerkraut",
    "Thüringer Rostbratwurst",
    "Nord-Ost Matjeshering",
    "Gorgonzola Telino",
    "Mascarpone Fabioli",
    "Geitost",
    "Sasquatch Ale",
    "Steeleye Stout",
    "Inlagd Sill",
    "Gravad lax",
    "Côte de Blaye",
    "Chartreuse verte",
    "Boston Crab Meat",
    "Jack's New England Clam Chowder",
    "Singaporean Hokkien Fried Mee",
    "Ipoh Coffee",
    "Gula Malacca",
    "Rogede sild",
    "Spegesild",
    "Zaanse koeken",
    "Chocolade",
    "Maxilaku",
    "Valkoinen suklaa",
    "Manjimup Dried Apples",
    "Filo Mix",
    "Perth Pasties",
    "Tourtière",
    "Pâté chinois",
    "Gnocchi di nonna Alice",
    "Ravioli Angelo",
    "Escargots de Bourgogne",
    "Raclette Courdavault",
    "Camembert Pierrot",
    "Sirop d'érable",
    "Tarte au sucre",
    "Vegie-spread",
    "Wimmers gute Semmelknödel",
    "Louisiana Fiery Hot Pepper Sauce",
    "Louisiana Hot Spiced Okra",
    "Laughing Lumberjack Lager",
    "Scottish Longbreads",
    "Gudbrandsdalsost",
    "Outback Lager",
    "Flotemysost",
    "Mozzarella di Giovanni",
    "Röd Kaviar",
    "Longlife Tofu",
    "Rhönbräu Klosterbier",
    "Lakkalikööri",
    "Original Frankfurter grüne Soße"
  ];

  let customername: string[] = [
    "Maria",
    "Ana Trujillo",
    "Antonio Moreno",
    "Thomas Hardy",
    "Christina Berglund",
    "Hanna Moos",
    "Frédérique Citeaux",
    "Martín Sommer",
    "Laurence Lebihan",
    "Elizabeth Lincoln",
    "Victoria Ashworth",
    "Patricio Simpson",
    "Francisco Chang",
    "Yang Wang",
    "Pedro Afonso",
    "Elizabeth Brown",
    "Sven Ottlieb",
    "Janine Labrune",
    "Ann Devon",
    "Roland Mendel",
    "Aria Cruz",
    "Diego Roel",
    "Martine Rancé",
    "Maria Larsson",
    "Peter Franken",
    "Carine Schmitt",
    "Paolo Accorti",
    "Lino Rodriguez",
    "Eduardo Saavedra",
    "José Pedro Freyre",
    "André Fonseca",
    "Howard Snyder",
    "Manuel Pereira",
    "Mario Pontes",
    "Carlos Hernández",
    "Yoshi Latimer",
    "Patricia McKenna",
    "Helen Bennett",
    "Philip Cramer",
    "Daniel Tonini",
    "Annette Roulet",
    "Yoshi Tannamuri",
    "John Steel",
    "Renate Messner",
    "Jaime Yorres",
    "Carlos González",
    "Felipe Izquierdo",
    "Fran Wilson",
    "Giovanni Rovelli",
    "Catherine Dewey",
    "Jean Fresnière",
    "Alexander Feuer",
    "Simon Crowther",
    "Yvonne Moncada",
    "Rene Phillips",
    "Henriette Pfalzheim",
    "Marie Bertrand",
    "Guillermo Fernández",
    "Georg Pipps",
    "Isabel de Castro",
    "Bernardo Batista",
    "Lúcia Carvalho",
    "Horst Kloss",
    "Sergio Gutiérrez",
    "Paula Wilson",
    "Maurizio Moroni",
    "Janete Limeira",
    "Michael Holz",
    "Alejandra Camino",
    "Jonas Bergulfsen",
    "Jose Pavarotti",
    "Hari Kumar",
    "Jytte Petersen",
    "Dominique Perrier",
    "Art Braunschweiger",
    "Pascale Cartrain",
    "Liz Nixon",
    "Liu Wong",
    "Karin Josephs",
    "Miguel Angel Paolino",
    "Anabela Domingues",
    "Helvetius Nagy",
    "Palle Ibsen",
    "Mary Saveley",
    "Paul Henriot",
    "Rita Müller",
    "Pirkko Koskitalo",
    "Paula Parente",
    "Karl Jablonski",
    "Matti Karttunen",
    "Zbyszek Piestrzeniewicz"
  ];

  let customeraddress: string[] = [
    "507 - 20th Ave. E.\r\nApt. 2A",
    "908 W. Capital Way",
    "722 Moss Bay Blvd.",
    "4110 Old Redmond Rd.",
    "14 Garrett Hill",
    "Coventry House\r\nMiner Rd.",
    "Edgeham Hollow\r\nWinchester Way",
    "4726 - 11th Ave. N.E.",
    "7 Houndstooth Rd.",
    "59 rue de l'Abbaye",
    "Luisenstr. 48",
    "908 W. Capital Way",
    "722 Moss Bay Blvd.",
    "4110 Old Redmond Rd.",
    "14 Garrett Hill",
    "Coventry House\r\nMiner Rd.",
    "Edgeham Hollow\r\nWinchester Way",
    "7 Houndstooth Rd.",
    "2817 Milton Dr.",
    "Kirchgasse 6",
    "Sierras de Granada 9993",
    "Mehrheimerstr. 369",
    "Rua da Panificadora, 12",
    "2817 Milton Dr.",
    "Mehrheimerstr. 369"
  ];

  let quantityperunit: string[] = [
    "10 boxes x 20 bags",
    "24 - 12 oz bottles",
    "12 - 550 ml bottles",
    "48 - 6 oz jars",
    "36 boxes",
    "12 - 8 oz jars",
    "12 - 1 lb pkgs.",
    "12 - 12 oz jars",
    "18 - 500 g pkgs.",
    "12 - 200 ml jars",
    "1 kg pkg.",
    "10 - 500 g pkgs.",
    "2 kg box",
    "40 - 100 g pkgs.",
    "24 - 250 ml bottles",
    "32 - 500 g boxes",
    "20 - 1 kg tins",
    "16 kg pkg.",
    "10 boxes x 12 pieces",
    "30 gift boxes",
    "24 pkgs. x 4 pieces",
    "24 - 500 g pkgs.",
    "12 - 250 g pkgs.",
    "12 - 355 ml cans",
    "20 - 450 g glasses",
    "100 - 250 g bags"
  ];

  let orderID: number = 10248;
  let k: number = 1;
  for (let i: number = 0; i < 1000; i++) {
    k = k > 9 ? 1 : k;
    lazyLoadData.push({
      OrderID: orderID + i,
      CustomerID: customerid[Math.floor(Math.random() * customerid.length)],
      CustomerName:
        customername[Math.floor(Math.random() * customername.length)],
      CustomerAddress:
        customeraddress[Math.floor(Math.random() * customeraddress.length)],
      ProductName: product[Math.floor(Math.random() * product.length)],
      ProductID: i,
      Quantity:
        quantityperunit[Math.floor(Math.random() * quantityperunit.length)],
      Id: k
    });
    k++;
  }
  return lazyLoadData;
}

Limitations

The following features are not supported in the immutable mode:

  • Frozen rows and columns
  • Row Template
  • Detail Template
  • Hierarchy Grid
  • Column reorder
  • Virtualization
  • Infinite scroll
  • Grouping