MRT logoMaterial React Table

React Query (Remote) Example

This is just like the Remote Data Fetching Example, but react-query is used to simplify all the state management of the fetching and loading of data.

React Query is by far the best way to fetch remote data in React. It has features like caching, refetching, polling, pagination, and more that work together very well with table logic as seen in this example.

Also, be sure to check out the Virtualized Example, which shows off the use of another TanStack library, React Virtual, to render thousands of rows at once while still maintaining great performance.

CRUD Examples
More Examples

Demo

Open StackblitzOpen Code SandboxOpen on GitHub
0-0 of 0

Source Code

1import { useMemo, useState } from 'react';
2import {
3 MaterialReactTable,
4 useMaterialReactTable,
5 type MRT_ColumnDef,
6 type MRT_ColumnFiltersState,
7 type MRT_PaginationState,
8 type MRT_SortingState,
9} from 'material-react-table';
10import { IconButton, Tooltip } from '@mui/material';
11import RefreshIcon from '@mui/icons-material/Refresh';
12import {
13 QueryClient,
14 QueryClientProvider,
15 keepPreviousData,
16 useQuery,
17} from '@tanstack/react-query'; //note: this is TanStack React Query V5
18
19//Your API response shape will probably be different. Knowing a total row count is important though.
20type UserApiResponse = {
21 data: Array<User>;
22 meta: {
23 totalRowCount: number;
24 };
25};
26
27type User = {
28 firstName: string;
29 lastName: string;
30 address: string;
31 state: string;
32 phoneNumber: string;
33 lastLogin: Date;
34};
35
36const Example = () => {
37 //manage our own state for stuff we want to pass to the API
38 const [columnFilters, setColumnFilters] = useState<MRT_ColumnFiltersState>(
39 [],
40 );
41 const [globalFilter, setGlobalFilter] = useState('');
42 const [sorting, setSorting] = useState<MRT_SortingState>([]);
43 const [pagination, setPagination] = useState<MRT_PaginationState>({
44 pageIndex: 0,
45 pageSize: 10,
46 });
47
48 //consider storing this code in a custom hook (i.e useFetchUsers)
49 const {
50 data: { data = [], meta } = {}, //your data and api response will probably be different
51 isError,
52 isRefetching,
53 isLoading,
54 refetch,
55 } = useQuery<UserApiResponse>({
56 queryKey: [
57 'table-data',
58 columnFilters, //refetch when columnFilters changes
59 globalFilter, //refetch when globalFilter changes
60 pagination.pageIndex, //refetch when pagination.pageIndex changes
61 pagination.pageSize, //refetch when pagination.pageSize changes
62 sorting, //refetch when sorting changes
63 ],
64 queryFn: async () => {
65 const fetchURL = new URL('/api/data', location.origin);
66
67 //read our state and pass it to the API as query params
68 fetchURL.searchParams.set(
69 'start',
70 `${pagination.pageIndex * pagination.pageSize}`,
71 );
72 fetchURL.searchParams.set('size', `${pagination.pageSize}`);
73 fetchURL.searchParams.set('filters', JSON.stringify(columnFilters ?? []));
74 fetchURL.searchParams.set('globalFilter', globalFilter ?? '');
75 fetchURL.searchParams.set('sorting', JSON.stringify(sorting ?? []));
76
77 //use whatever fetch library you want, fetch, axios, etc
78 const response = await fetch(fetchURL.href);
79 const json = (await response.json()) as UserApiResponse;
80 return json;
81 },
82 placeholderData: keepPreviousData, //don't go to 0 rows when refetching or paginating to next page
83 });
84
85 const columns = useMemo<MRT_ColumnDef<User>[]>(
86 //column definitions...
120 );
121
122 const table = useMaterialReactTable({
123 columns,
124 data,
125 initialState: { showColumnFilters: true },
126 manualFiltering: true, //turn off built-in client-side filtering
127 manualPagination: true, //turn off built-in client-side pagination
128 manualSorting: true, //turn off built-in client-side sorting
129 muiToolbarAlertBannerProps: isError
130 ? {
131 color: 'error',
132 children: 'Error loading data',
133 }
134 : undefined,
135 onColumnFiltersChange: setColumnFilters,
136 onGlobalFilterChange: setGlobalFilter,
137 onPaginationChange: setPagination,
138 onSortingChange: setSorting,
139 renderTopToolbarCustomActions: () => (
140 <Tooltip arrow title="Refresh Data">
141 <IconButton onClick={() => refetch()}>
142 <RefreshIcon />
143 </IconButton>
144 </Tooltip>
145 ),
146 rowCount: meta?.totalRowCount ?? 0,
147 state: {
148 columnFilters,
149 globalFilter,
150 isLoading,
151 pagination,
152 showAlertBanner: isError,
153 showProgressBars: isRefetching,
154 sorting,
155 },
156 });
157
158 return <MaterialReactTable table={table} />;
159};
160
161const queryClient = new QueryClient();
162
163const ExampleWithReactQueryProvider = () => (
164 //App.tsx or AppProviders file. Don't just wrap this component with QueryClientProvider! Wrap your whole App!
165 <QueryClientProvider client={queryClient}>
166 <Example />
167 </QueryClientProvider>
168);
169
170export default ExampleWithReactQueryProvider;
171

View Extra Storybook Examples