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 { lazy, Suspense, 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 'users-list',
58 {
59 columnFilters, //refetch when columnFilters changes
60 globalFilter, //refetch when globalFilter changes
61 pagination, //refetch when pagination changes
62 sorting, //refetch when sorting changes
63 },
64 ],
65 queryFn: async () => {
66 const fetchURL = new URL('/api/data', location.origin);
67
68 //read our state and pass it to the API as query params
69 fetchURL.searchParams.set(
70 'start',
71 `${pagination.pageIndex * pagination.pageSize}`,
72 );
73 fetchURL.searchParams.set('size', `${pagination.pageSize}`);
74 fetchURL.searchParams.set('filters', JSON.stringify(columnFilters ?? []));
75 fetchURL.searchParams.set('globalFilter', globalFilter ?? '');
76 fetchURL.searchParams.set('sorting', JSON.stringify(sorting ?? []));
77
78 //use whatever fetch library you want, fetch, axios, etc
79 const response = await fetch(fetchURL.href);
80 const json = (await response.json()) as UserApiResponse;
81 return json;
82 },
83 placeholderData: keepPreviousData, //don't go to 0 rows when refetching or paginating to next page
84 });
85
86 const columns = useMemo<MRT_ColumnDef<User>[]>(
87 //column definitions...
121 );
122
123 const table = useMaterialReactTable({
124 columns,
125 data,
126 initialState: { showColumnFilters: true },
127 manualFiltering: true, //turn off built-in client-side filtering
128 manualPagination: true, //turn off built-in client-side pagination
129 manualSorting: true, //turn off built-in client-side sorting
130 muiToolbarAlertBannerProps: isError
131 ? {
132 color: 'error',
133 children: 'Error loading data',
134 }
135 : undefined,
136 onColumnFiltersChange: setColumnFilters,
137 onGlobalFilterChange: setGlobalFilter,
138 onPaginationChange: setPagination,
139 onSortingChange: setSorting,
140 renderTopToolbarCustomActions: () => (
141 <Tooltip arrow title="Refresh Data">
142 <IconButton onClick={() => refetch()}>
143 <RefreshIcon />
144 </IconButton>
145 </Tooltip>
146 ),
147 rowCount: meta?.totalRowCount ?? 0,
148 state: {
149 columnFilters,
150 globalFilter,
151 isLoading,
152 pagination,
153 showAlertBanner: isError,
154 showProgressBars: isRefetching,
155 sorting,
156 },
157 });
158
159 return <MaterialReactTable table={table} />;
160};
161
162//react query setup in App.tsx
163const ReactQueryDevtoolsProduction = lazy(() =>
164 import('@tanstack/react-query-devtools/build/modern/production.js').then(
165 (d) => ({
166 default: d.ReactQueryDevtools,
167 }),
168 ),
169);
170
171const queryClient = new QueryClient();
172
173export default function App() {
174 return (
175 <QueryClientProvider client={queryClient}>
176 <Example />
177 <Suspense fallback={null}>
178 <ReactQueryDevtoolsProduction />
179 </Suspense>
180 </QueryClientProvider>
181 );
182}
183

View Extra Storybook Examples