Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

tanstack v8 react table - how to sort server-side with manualSorting

I am new to V8 of tanstack react table ... appears to be quite different to V7 in some areas and would love some advice.

I need to sort server-side using apollo graphql.

From reading the docs I know that you need to use the prop "manualSorting"...It just isn't clear exactly what to do from there

  const [sorting, setSorting] = useState<SortingState>([]);

  const hasVar = Boolean(reactiveVar);

  const selectedRowId = useReactiveVar(
    reactiveVar ?? makeVar<SelectedID>(null)
  );

  const { controlledPageCount, setControlledPageCount, formatLoadSorts } =
    useLoadTableUtils();

  const serverSideTable = useReactTable({
    data,
    columns,
    pageCount: controlledPageCount,
    state: {
      sorting,
      pagination,
    },
    onPaginationChange: setPagination,
    manualPagination: true,
    onSortingChange: setSorting,
    manualSorting: true,
    debugTable: true,
    getCoreRowModel: getCoreRowModel(),
    enableSorting: true,
    sortingFns,
  });
like image 796
devmike9113 Avatar asked Nov 16 '25 03:11

devmike9113


1 Answers

To implement manual sorting in react-table v8, you will need to follow the steps below:

  1. Initialize the sorting state using the useState hook.
const [sorting, setSorting] = useState<SortingState>([]);
  1. Pass the sorting state and setSorting function to useReactTable's state.sorting and onSortingChange props.
const serverSideTable = useReactTable({
  ...
  state: {
    sorting,
  },
  onSortingChange: setSorting,
  ...
});
  1. Enable manual sorting by setting the manualSorting prop to true.
const serverSideTable = useReactTable({
  ...
  manualSorting: true,
  ...
});
  1. When the user clicks on a column header to sort the data, react-table will call the setSorting function and update the sorting state. You can then use this state to send a request to your server to retrieve the sorted data.

As I can see, in your example you have already done that. Further, everything is very simple, you modify sorting as you need and send a request with it to the server.

For example I use RTK Query to get data and nest-paginate on the backend. Here is my simple implementation example:

// UsersTable.tsx

import type { SortingState } from '@tanstack/react-table';
import React from 'react';

import { ReactTable } from '@/components/ui/ReactTable';
import { useGetUsersQuery } from '@/store/user/user.api';

import { columns } from './columns';

export const UsersTable = () => {
  const [sorting, setSorting] = React.useState<SortingState>([]);

  const { data, isLoading, isFetching } = useGetUsersQuery({
    sortBy: sorting.map((s) => `${s.id}:${s.desc ? 'DESC' : 'ASC'}`).join(','),
  });

  return (
    <ReactTable
      data={data?.data || []}
      columns={columns}
      isLoading={isLoading || isFetching}
      sorting={sorting}
      setSorting={setSorting}
    />
  );
};
// ReactTable.tsx

import type {
  ColumnDef,
  OnChangeFn,
  SortingState,
} from '@tanstack/react-table';
import {
  flexRender,
  getCoreRowModel,
  useReactTable,
} from '@tanstack/react-table';
import { ArrowDown, ArrowUp } from 'phosphor-react';
import React from 'react';

import { Table, TableHead, TableHeadCell } from '../Table';
import { TableBody } from '../Table/TableBody';
import { TableCell } from '../Table/TableCell';
import { TableRow } from '../Table/TableRow';

export interface TableProps<TData> {
  data: TData[];
  columns: ColumnDef<TData>[];
  isLoading?: boolean;
  sorting?: SortingState;
  setSorting?: OnChangeFn<SortingState>;
}

export const ReactTable = <TData extends object>({
  data,
  columns,
  isLoading,
  sorting,
  setSorting,
}: TableProps<TData>) => {
  const memoizedData = React.useMemo(() => data, [data]);
  const memoizedColumns = React.useMemo(() => columns, [columns]);

  const table = useReactTable({
    data: memoizedData,
    columns: memoizedColumns,
    state: {
      sorting,
    },
    manualSorting: true,
    onSortingChange: setSorting,
    getCoreRowModel: getCoreRowModel(),
  });

  const isNoDataFound =
    !isLoading && (!memoizedData || memoizedData.length === 0);

  return (
    <div className="relative overflow-hidden border bg-white dark:border-gray-700 dark:bg-gray-900 sm:rounded-xl">
      {!isNoDataFound &&
        (isLoading ? (
          <div className="flex h-full w-full items-center justify-center p-8">
            Loading...
          </div>
        ) : (
          <Table>
            <TableHead>
              {table.getHeaderGroups().map((headerGroup) => (
                <tr key={headerGroup.id}>
                  {headerGroup.headers.map((header) => {
                    return (
                      <TableHeadCell key={header.id} colSpan={header.colSpan}>
                        {header.isPlaceholder ? null : (
                          <div
                            {...{
                              className: header.column.getCanSort()
                                ? 'select-none cursor-pointer flex items-center gap-1'
                                : '',
                              onClick: header.column.getToggleSortingHandler(),
                            }}
                          >
                            {flexRender(
                              header.column.columnDef.header,
                              header.getContext(),
                            )}
                            {{
                              asc: <ArrowDown className="h-4 w-4" />,
                              desc: <ArrowUp className="h-4 w-4" />,
                            }[header.column.getIsSorted() as string] ?? null}
                          </div>
                        )}
                      </TableHeadCell>
                    );
                  })}
                </tr>
              ))}
            </TableHead>
            <TableBody>
              {table.getRowModel().rows.map((row) => (
                <TableRow key={row.id}>
                  {row.getVisibleCells().map((cell) => {
                    return (
                      <TableCell key={cell.id}>
                        {flexRender(
                          cell.column.columnDef.cell,
                          cell.getContext(),
                        )}
                      </TableCell>
                    );
                  })}
                </TableRow>
              ))}
            </TableBody>
          </Table>
        ))}
    </div>
  );
};

I haven't worked with GraphQL Apollo yet, so I can't say exactly how it's implemented there, but most likely you will need to pass the sorting state as variables in your GraphQL query and use those variables to sort the data on the server side.

like image 123
monotype Avatar answered Nov 18 '25 19:11

monotype



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!