Working with Data

When working with data, you will mostly interact with the <DataSource /> component, which is responsible for handling and managing the data and passing it down to the <InfiniteTable /> component, which is the rendering engine for the DataGrid.

So we provide those two components (as named exports) inside @infinite-table/infinite-react package:

  • <DataSource /> - our data-handling component
  • <InfiniteTable /> - our virtualized component

The <DataSource/> component is responsible for the data the management layer.

Note

Probably the most important prop for the <DataSource /> component is the idProperty prop. It specifies the property of the data object that is used as a unique identifier for data rows/items.

<DataSource<DATA_TYPE>
  idProperty="id"
  data={[]} // or a Promise or function returning a Promise.

The <DataSource /> is a generic React TypeScript component that can be bound to an array of items of the generic type.

Note

In this documentation, we'll use DATA_TYPE when referring to the generic type. Rarely, we'll use T.

<DataSource<DATA_TYPE>>
  <InfiniteTable<DATA_TYPE> />
</DataSource>

Most of our examples in these docs have a Developer or Employee TypeScript data type used as the generic type for the <DataSource /> component.

import { DataSource } from '@infinite-table/infinite-react';

type Employee = {
  id: string | number;
  name: string;
  salary: number;
  department: string;
  company: string;
};

const employees: Employee[] = [
  { id: 1, name: 'Bob', salary: 10_000, department: 'IT', company: 'Bobsons' },
  {
    id: 2,
    name: 'Alice',
    salary: 20_000,
    department: 'IT',
    company: 'Bobsons',
  },
  { id: 3, name: 'John', salary: 30_000, department: 'IT', company: 'Bobsons' },
];

<DataSource<Employee> primaryKey={'id'} data={employees}

In the snippet above, we see 3 important details:

  1. the component is bound to the Employee type
  2. we use a primaryKey property - here it is id, but since the bound type is Employee, primaryKey is keyof Employee
  3. we pass the employees array as the data property.

Note

The data prop can be either:

  • an array of the bound generic type - here Employee[]
  • a Promise tha resolves to an array like the above
  • a function that returns any of the above
Data loading example with promise
View Mode
Fork
import {
  InfiniteTable,
  DataSource,
  InfiniteTableColumn,
} from '@infinite-table/infinite-react';
import * as React from 'react';

type Employee = {
  id: string | number;
  name: string;
  salary: number;
  department: string;
  company: string;
};

const employees: Employee[] = [
  {
    id: 1,
    name: 'Bob',
    salary: 10_000,
    department: 'IT',
    company: 'Bobsons',
  },
  {
    id: 2,
    name: 'Alice',
    salary: 20_000,
    department: 'IT',
    company: 'Bobsons',
  },
  {
    id: 3,
    name: 'John',
    salary: 30_000,
    department: 'IT',
    company: 'Bobsons',
  },
  {
    id: 4,
    name: 'Jane',
    salary: 35_000,
    department: 'Marketing',
    company: 'Janies',
  },
  {
    id: 5,
    name: 'Mary',
    salary: 40_000,
    department: 'Marketing',
    company: 'Janies',
  },
];

// simulate data-loading with a 1500ms delay
const data = new Promise<Employee[]>((resolve) => {
  setTimeout(() => {
    resolve(employees);
  }, 1500);
});

export default function App() {
  return (
    <DataSource<Employee> data={data} primaryKey="id">
      <InfiniteTable<Employee> columnDefaultWidth={130} columns={columns} />
    </DataSource>
  );
}

const columns: Record<string, InfiniteTableColumn<Employee>> = {
  id: {
    field: 'id',
    type: 'number',
    defaultWidth: 80,
  },
  name: {
    field: 'name',
  },
  salary: { field: 'salary', type: 'number' },
  department: { field: 'department', header: 'Dep.' },
  company: { field

Data Loading Strategies

We're aware there are countless strategies for loading data - each with its own strengths. We decided we should focus on building what we do best, namely building virtualized components, so we encourage you to use your preferred data-fetching library/solution. This being said, we still provide you with the flexibility you need when using the <DataSource/>, so here's what you can use for the data prop of the component:

  • an array of the bound type
  • a Promise that resolves to an array of the bound type
  • a function that returns any of the above

While you're loading the data, you can always render a loading indicator - pass the loading prop into the component (along with loadingText prop in the <InfiniteTable /> component if you want to customize the message).

Using fetch

For basic datasets, which have simple data requirements, using fetch is probably sufficient, so here is an example:

Using fetch for remote data
View Mode
Fork
import { InfiniteTable, DataSource } from '@infinite-table/infinite-react';
import * as React from 'react';

import { columns, Employee } from './columns';

export default function App() {
  return (
    <DataSource<Employee> data={dataSource} primaryKey="id">
      <InfiniteTable<Employee> columns={columns} />
    </DataSource>
  );
}

const dataSource = () => {
  return fetch('https://infinite-table.com/.netlify/functions/json-server' + '/employees10k')
    .then((r) => r.json())
    .then((data: Employee[]) => {

Re-fetching on change

It's important to note you can re-fetch data by changing the reference you pass as the data prop to the <DataSource/> component.

Note

Passing another data function, will cause the component to re-execute the function and thus load new data.

Alternatively, you can use the refetchKey prop to trigger a re-fetch - give it a new value (eg: use it as a counter, and increment it) and the component will re-fetch the data.

Re-fetching data
View Mode
Fork
import { InfiniteTable, DataSource } from '@infinite-table/infinite-react';
import * as React from 'react';

import { columns, Employee } from './columns';

const getDataSourceFor = (size: string) => {
  if (size === '0') {
    return () => Promise.resolve([]);
  }
  return () => {
    return fetch('https://infinite-table.com/.netlify/functions/json-server' + '/employees' + size)
      .then((r) => r.json())
      .then((data: Employee[]) => data);
  };
};

export default function App() {
  const [dataSourceSize, setDataSourceSize] = React.useState<string>('10');

  const dataSource = React.useMemo(() => {
    return getDataSourceFor(dataSourceSize);
  }, [dataSourceSize]);
  return (
    <div
      style={{
        display: 'flex',
        flex: 1,
        color: 'var(--infinite-cell-color)',
        flexFlow: 'column',
        background: 'var(--infinite-background)',
      }}
    >
      <p style={{ padding: 10 }}>Please select the size of the datasource:</p>
      <div style={{ padding: 10 }}>
        <select
          style={{
            margin: '10px 0',
            display: 'inline-block',
            background: 'var(--infinite-background)',
            color: 'currentColor',
            padding: 'var(--infinite-space-3)',
          }}
          value={dataSourceSize}
          onChange={(event) => {
            const newSize = event.target.value as string;

            setDataSourceSize(newSize);
          }}
        >
          <option value="0">no items</option>
          <option value="10">10 items</option>
          <option value="100">100 items</option>
          <option value="1k">1k items</option>
          <option value="10k">10k items</option>
        </select>
      </div>
      <DataSource<Employee> data={dataSource} primaryKey="id">
        <InfiniteTable<Employee> columns={columns} columnDefaultWidth={150} />
      </DataSource>
    </div>

Live Updates

You can update your data in real-time by using our DataSource API.

DataSource API

Read more about how to use our API to update your data in real-time