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

View Extra Storybook Examples