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(
66 '/api/data',
67 process.env.NODE_ENV === 'production'
68 ? 'https://www.material-react-table.com'
69 : 'http://localhost:3000',
70 );
71
72 //read our state and pass it to the API as query params
73 fetchURL.searchParams.set(
74 'start',
75 `${pagination.pageIndex * pagination.pageSize}`,
76 );
77 fetchURL.searchParams.set('size', `${pagination.pageSize}`);
78 fetchURL.searchParams.set('filters', JSON.stringify(columnFilters ?? []));
79 fetchURL.searchParams.set('globalFilter', globalFilter ?? '');
80 fetchURL.searchParams.set('sorting', JSON.stringify(sorting ?? []));
81
82 //use whatever fetch library you want, fetch, axios, etc
83 const response = await fetch(fetchURL.href);
84 const json = (await response.json()) as UserApiResponse;
85 return json;
86 },
87 placeholderData: keepPreviousData, //don't go to 0 rows when refetching or paginating to next page
88 });
89
90 const columns = useMemo<MRT_ColumnDef<User>[]>(
91 //column definitions...
125 );
126
127 const table = useMaterialReactTable({
128 columns,
129 data,
130 initialState: { showColumnFilters: true },
131 manualFiltering: true, //turn off built-in client-side filtering
132 manualPagination: true, //turn off built-in client-side pagination
133 manualSorting: true, //turn off built-in client-side sorting
134 muiToolbarAlertBannerProps: isError
135 ? {
136 color: 'error',
137 children: 'Error loading data',
138 }
139 : undefined,
140 onColumnFiltersChange: setColumnFilters,
141 onGlobalFilterChange: setGlobalFilter,
142 onPaginationChange: setPagination,
143 onSortingChange: setSorting,
144 renderTopToolbarCustomActions: () => (
145 <Tooltip arrow title="Refresh Data">
146 <IconButton onClick={() => refetch()}>
147 <RefreshIcon />
148 </IconButton>
149 </Tooltip>
150 ),
151 rowCount: meta?.totalRowCount ?? 0,
152 state: {
153 columnFilters,
154 globalFilter,
155 isLoading,
156 pagination,
157 showAlertBanner: isError,
158 showProgressBars: isRefetching,
159 sorting,
160 },
161 });
162
163 return <MaterialReactTable table={table} />;
164};
165
166const queryClient = new QueryClient();
167
168const ExampleWithReactQueryProvider = () => (
169 //App.tsx or AppProviders file. Don't just wrap this component with QueryClientProvider! Wrap your whole App!
170 <QueryClientProvider client={queryClient}>
171 <Example />
172 </QueryClientProvider>
173);
174
175export default ExampleWithReactQueryProvider;
176

View Extra Storybook Examples