# Sorting and Filtering the Data Yourself

> Pass data you already sorted and filtered to the Infinite Table DataSource - from your own code, a server, or a data-fetching library like TanStack Query

Canonical page: https://infinite-table.com/docs/learn/working-with-data/sorting-and-filtering-the-data-yourself

By default, the `<DataSource />` sorts and filters the data in the browser - for array data, for a `Promise`, for a [`data`](https://infinite-table.com/docs/reference/datasource-props/index.md#data) function, and also when [`sortInfo`](https://infinite-table.com/docs/reference/datasource-props/index.md#sortInfo) or [`filterValue`](https://infinite-table.com/docs/reference/datasource-props/index.md#filterValue) are controlled.

When you sort or filter the data yourself - on a server, in a data-fetching library like TanStack Query, or in your own code - tell the `<DataSource />` not to do it again, with [`shouldReloadData`](https://infinite-table.com/docs/reference/datasource-props/index.md#shouldReloadData):

```tsx
<DataSource<Developer>
  primaryKey="id"
  data={rows}
  sortInfo={sortInfo}
  onSortInfoChange={setSortInfo}
  filterValue={filterValue}
  onFilterValueChange={setFilterValue}
  shouldReloadData={{ sortInfo: true, filterValue: true }}
/>
```

- with a [`data`](https://infinite-table.com/docs/reference/datasource-props/index.md#data) function, it's called again on every sort or filter change, with the `sortInfo` and `filterValue` in its params;
- with array data, you pass a new array every time the sorting or the filtering changes (eg from [`onSortInfoChange`](https://infinite-table.com/docs/reference/datasource-props/index.md#onSortInfoChange) and [`onFilterValueChange`](https://infinite-table.com/docs/reference/datasource-props/index.md#onFilterValueChange)).

Either way, the rows are shown as they come in - they are not sorted or filtered again in the browser.

Grouping and pivoting are always done in the browser - unless you use [`lazyLoad`](https://infinite-table.com/docs/reference/datasource-props/index.md#lazyLoad), where the server returns the groups.

## Reusing the built-in sorting and filtering

To sort and filter the data the same way the `<DataSource />` does, use the functions it uses:

- `multisort(sortInfo, array)` - the built-in sorting for flat data (it sorts the array in place, so pass a copy);
- `defaultFilterFunction(param)` - the built-in column filtering for one row. It needs the row, its index, the array, the primary key, and the column filters with their filter types - the default `filterTypes` are exported too.

```ts
import {
  defaultFilterFunction,
  filterTypes,
  multisort,
} from '@infinite-table/infinite-react';

function sortAndFilter(rows, sortInfo, filterValue) {
  const filtered = rows.filter((data, index, dataArray) =>
    defaultFilterFunction({
      data,
      index,
      dataArray,
      primaryKey: data.id,
      filterValue,
      filterTypes,
    }),
  );
  return multisort(sortInfo, filtered);
}
```

If you configure custom [`filterTypes`](https://infinite-table.com/docs/reference/datasource-props/index.md#filterTypes) on the `<DataSource />`, pass the same ones to `defaultFilterFunction`.

## With TanStack Query

The query key includes the sorting and the filtering, so every change runs a new query. Thanks to `placeholderData: keepPreviousData`, the previous rows stay on screen until the new ones arrive - and because the `<DataSource />` doesn't sort or filter them itself, they don't change until the query resolves.

**Example: Sorting and filtering with TanStack Query**

```ts
import {
  DataSource,
  DataSourcePropFilterValue,
  DataSourceSingleSortInfo,
  InfiniteTable,
  InfiniteTableColumn,
  defaultFilterFunction,
  filterTypes,
  multisort,
} from '@infinite-table/infinite-react';
import {
  QueryClient,
  QueryClientProvider,
  keepPreviousData,
  useQuery,
} from '@tanstack/react-query';
import * as React from 'react';

type Developer = {
  id: number;
  firstName: string;
  country: string;
  stack: string;
  age: number;
};

const developers: Developer[] = [
  { id: 1, firstName: 'Bob', country: 'USA', stack: 'backend', age: 30 },
  { id: 2, firstName: 'Alice', country: 'France', stack: 'frontend', age: 25 },
  { id: 3, firstName: 'Carl', country: 'USA', stack: 'full-stack', age: 40 },
  { id: 4, firstName: 'Dana', country: 'France', stack: 'backend', age: 35 },
  { id: 5, firstName: 'Eve', country: 'Germany', stack: 'frontend', age: 28 },
  { id: 6, firstName: 'Frank', country: 'Germany', stack: 'backend', age: 45 },
];

// pretend this runs on a server: it filters and sorts the rows,
// with the same functions the DataSource uses
function fetchDevelopers(
  sortInfo: DataSourceSingleSortInfo<Developer>[],
  filterValue: DataSourcePropFilterValue<Developer>,
) {
  const filtered = developers.filter((data, index, dataArray) =>
    defaultFilterFunction({
      data,
      index,
      dataArray,
      primaryKey: data.id,
      filterValue,
      filterTypes,
    }),
  );
  const rows = multisort(sortInfo, filtered);

  return new Promise<Developer[]>((resolve) => {
    setTimeout(() => resolve(rows), 600);
  });
}

const columns: Record<string, InfiniteTableColumn<Developer>> = {
  firstName: { field: 'firstName', header: 'First name' },
  country: { field: 'country' },
  stack: { field: 'stack' },
  age: { field: 'age', type: 'number' },
};

const queryClient = new QueryClient();
const noRows: Developer[] = [];

function Developers() {
  const [sortInfo, setSortInfo] = React.useState<
    DataSourceSingleSortInfo<Developer>[]
  >([]);
  const [filterValue, setFilterValue] = React.useState<
    DataSourcePropFilterValue<Developer>
  >([]);

  const { data, isFetching } = useQuery({
    queryKey: ['developers', sortInfo, filterValue],
    queryFn: () => fetchDevelopers(sortInfo, filterValue),
    placeholderData: keepPreviousData,
  });

  return (
    <>
      <p style={{ color: 'var(--infinite-cell-color)' }}>
        {isFetching ? 'Loading...' : 'Sort or filter a column'}
      </p>
      <DataSource<Developer>
        primaryKey="id"
        data={data ?? noRows}
        sortInfo={sortInfo}
        onSortInfoChange={setSortInfo}
        filterValue={filterValue}
        onFilterValueChange={setFilterValue}
        shouldReloadData={{ sortInfo: true, filterValue: true }}
      >
        <InfiniteTable<Developer> columns={columns} showColumnFilters />
      </DataSource>
    </>
  );
}

export default function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <Developers />
    </QueryClientProvider>
  );
}
```
