MRT logoMaterial React Table

Remote Data Example

You will most likely be using a remote data source for your table, which is fully supported. Here is an example of data being fetched from a remote server but also filtered, paginated, and sorted on the server.

Also, be sure to check out the TanStack React Query Example, which is very similar to this one, except it uses react-query to simplify much of the state management needed for fetching data.


Demo

Open StackblitzOpen Code SandboxOpen on GitHub

No records to display

Rows per page

0-0 of 0

Source Code

1import React, { FC, useEffect, useMemo, useState } from 'react';
2import MaterialReactTable, { MRT_ColumnDef } from 'material-react-table';
3import type {
4 ColumnFiltersState,
5 PaginationState,
6 SortingState,
7} from '@tanstack/react-table';
8
9type UserApiResponse = {
10 data: Array<User>;
11 meta: {
12 totalRowCount: number;
13 };
14};
15
16type User = {
17 firstName: string;
18 lastName: string;
19 address: string;
20 state: string;
21 phoneNumber: string;
22};
23
24const Example: FC = () => {
25 //data and fetching state
26 const [data, setData] = useState<User[]>([]);
27 const [isError, setIsError] = useState(false);
28 const [isLoading, setIsLoading] = useState(false);
29 const [isRefetching, setIsRefetching] = useState(false);
30 const [rowCount, setRowCount] = useState(0);
31
32 //table state
33 const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]);
34 const [globalFilter, setGlobalFilter] = useState('');
35 const [sorting, setSorting] = useState<SortingState>([]);
36 const [pagination, setPagination] = useState<PaginationState>({
37 pageIndex: 0,
38 pageSize: 10,
39 });
40
41 //if you want to avoid useEffect, look at the React Query example instead
42 useEffect(() => {
43 const fetchData = async () => {
44 if (!data.length) {
45 setIsLoading(true);
46 } else {
47 setIsRefetching(true);
48 }
49
50 const url = new URL(
51 '/api/data',
52 process.env.NODE_ENV === 'production'
53 ? 'https://www.material-react-table.com'
54 : 'http://localhost:3000',
55 );
56 url.searchParams.set(
57 'start',
58 `${pagination.pageIndex * pagination.pageSize}`,
59 );
60 url.searchParams.set('size', `${pagination.pageSize}`);
61 url.searchParams.set('filters', JSON.stringify(columnFilters ?? []));
62 url.searchParams.set('globalFilter', globalFilter ?? '');
63 url.searchParams.set('sorting', JSON.stringify(sorting ?? []));
64
65 try {
66 const response = await fetch(url.href);
67 const json = (await response.json()) as UserApiResponse;
68 setData(json.data);
69 setRowCount(json.meta.totalRowCount);
70 } catch (error) {
71 setIsError(true);
72 console.error(error);
73 return;
74 }
75 setIsError(false);
76 setIsLoading(false);
77 setIsRefetching(false);
78 };
79 fetchData();
80 // eslint-disable-next-line react-hooks/exhaustive-deps
81 }, [
82 columnFilters,
83 globalFilter,
84 pagination.pageIndex,
85 pagination.pageSize,
86 sorting,
87 ]);
88
89 const columns = useMemo<MRT_ColumnDef<User>[]>(
90 () => [
91 {
92 accessorKey: 'firstName',
93 header: 'First Name',
94 },
95 //column definitions...
113 ],
114 [],
115 );
116
117 return (
118 <MaterialReactTable
119 columns={columns}
120 data={data}
121 enableRowSelection
122 getRowId={(row) => row.phoneNumber}
123 initialState={{ showColumnFilters: true }}
124 manualFiltering
125 manualPagination
126 manualSorting
127 muiToolbarAlertBannerProps={
128 isError
129 ? {
130 color: 'error',
131 children: 'Error loading data',
132 }
133 : undefined
134 }
135 onColumnFiltersChange={setColumnFilters}
136 onGlobalFilterChange={setGlobalFilter}
137 onPaginationChange={setPagination}
138 onSortingChange={setSorting}
139 rowCount={rowCount}
140 state={{
141 columnFilters,
142 globalFilter,
143 isLoading,
144 pagination,
145 showAlertBanner: isError,
146 showProgressBars: isRefetching,
147 sorting,
148 }}
149 />
150 );
151};
152
153export default Example;
154

View Extra Storybook Examples