Skip to main content
Version: 3.xx.xx

useTable

By using useTable, you are able to get properties that are compatible with Ant Design <Table> component. All features such as sorting, filtering and pagination comes as out of box.

Basic usage

Lets say that the data we are going to show on the table came like this from the endpoint:

https://api.fake-rest.refine.dev/posts
[
{
"id": 182,
"title": "A aspernatur rerum molestiae.",
"content": "Natus molestias incidunt voluptatibus. Libero delectus facilis...",
"status": "published"
},
{
"id": 989,
"title": "A molestiae vel voluptatem enim.",
"content": "Voluptas consequatur quia beatae. Ipsa est qui culpa deleniti...",
"status": "draft",
"createdAt": "2020-01-28T02:57:58.892Z"
}
]

If we want to make a sorting page where we show the id, title and content values:

/src/pages/posts/list.tsx
import { List, Table, TextField, useTable } from "@pankod/refine-antd";

export const PostList: React.FC = () => {
const { tableProps } = useTable<IPost>();

return (
<List>
<Table {...tableProps} rowKey="id">
<Table.Column dataIndex="id" title="ID" />
<Table.Column dataIndex="title" title="Title" />
<Table.Column dataIndex="content" title="Content" />
</Table>
</List>
);
};

interface IPost {
id: string;
title: string;
content: string;
status: "published" | "draft" | "rejected";
}
tip

In a page in resource given to <Refine> component, useTable decides which sources are going to be shown automatically. If you want to show the data that comes from the endpoint of another resource . You can do so with the resource: string option in the option object that the useTable(options) hook takes. If the resource option is given, syncWithLocation will not work.

useTable uses useMany while pulling data from the given resource.

Listing


info

If you want to make a change in the pagination of the <Table>. You should pass the pagination object of the tableProps to the pagination property of the <Table> as below.

const { tableProps } = useTable<IPost>();

<Table
{...tableProps}
rowKey="id"
pagination={{
...tableProps.pagination,
position: ["bottomCenter"],
size: "small",
}}
>
...
</Table>;

Sorting

If we want to give a column the sorting property, the corresponding <Table.Column> component must be given the sorter property.

/src/pages/posts/list.tsx
import {
List,
Table,
TextField,
useTable,
getDefaultSortOrder,
} from "@pankod/refine-antd";

export const PostList: React.FC = () => {
const { tableProps, sorter } = useTable<IPost>();

return (
<List>
<Table {...tableProps} rowKey="id">
<Table.Column
dataIndex="id"
title="ID"
render={(value) => <TextField value={value} />}
sorter
defaultSortOrder={getDefaultSortOrder("id", sorter)}
/>
<Table.Column
dataIndex="title"
title="Title"
render={(value) => <TextField value={value} />}
sorter={{ multiple: 1 }}
defaultSortOrder={getDefaultSortOrder("title", sorter)}
/>
<Table.Column dataIndex="content" title="Content" />
</Table>
</List>
);
};
caution

During the sorting process, the key property of your <Column /> component is used as the property name in the API request. If your Column component does not have a key value, the dataIndex property is used. It can be used when your DataIndex and your sorting key are different.

tip

When using multiple sorting, multiple value we had given to the sorter property specifies the priority of this column in sorting.

Table sorting in action

Initial sort status

/src/pages/posts/list.tsx
const { tableProps, sorter } = useTable<IPost>({
initialSorter: [
{
field: "title",
order: "asc",
},
],
});

By using initialSorter setting, you can select which field is going to start with which sorting status ("asc" or "desc").

caution

If you're using the initialSorter, don't forget to add getDefaultSortOrder to your <Table.Column> component. Otherwise, during filter and paging operations, the initialSorter might be lost.

...
<Table.Column
dataIndex="title"
title="Title"
sorter={{ multiple: 2 }}
defaultSortOrder={getDefaultSortOrder("title", sorter)}
/>
...

Filtering

Every post that comes from endpoint has a status value. This value can either be published or draft. We can show the status value with a Ant Design <TagField>:

/src/pages/posts/list.tsx
...
<Table.Column
dataIndex="status"
title="Status"
render={(value) => <TagField value={value} />}
/>
...

We can use the filterDropdown property to make filtering based on the status value. In order to do this, we need to put the filtering form inside the <FilterDropdown> component and pass the properties coming to the function to these component's properties:

/src/pages/posts/list.tsx
import {
List,
Table,
Radio,
FilterDropdown,
TagField,
useTable,
getDefaultSortOrder,
} from "@pankod/refine-antd";

export const PostList: React.FC = () => {
const { tableProps, sorter } = useTable<IPost>({
initialSorter: [
{
field: "title",
order: "asc",
},
],
});

return (
<List>
<Table {...tableProps} rowKey="id">
<Table.Column dataIndex="id" title="ID" sorter />
<Table.Column
dataIndex="title"
title="Title"
sorter={{ multiple: 2 }}
defaultSortOrder={getDefaultSortOrder("title", sorter)}
/>
<Table.Column
dataIndex="content"
title="Content"
sorter={{ multiple: 1 }}
/>
<Table.Column
dataIndex="status"
title="Status"
render={(value) => <TagField value={value} />}
filterDropdown={(props) => (
<FilterDropdown {...props}>
<Radio.Group>
<Radio value="published">Published</Radio>
<Radio value="draft">Draft</Radio>
<Radio value="rejected">Rejected</Radio>
</Radio.Group>
</FilterDropdown>
)}
/>
</Table>
</List>
);
};
Table filtering in action

Default filter value

In order to set a default filter value, you can use the initialFilter option of the useTable(options) hook.

/src/pages/posts/list.tsx
const { tableProps, sorter, filters } = useTable<IPost>({
initialSorter: [
{
field: "title",
order: "asc",
},
],
initialFilter: [
{
field: "status",
operator: "eq",
value: "draft",
},
],
});

If you give default filter values, defaultFilteredValue property needs to be properly given to the relevant <Table.Column> components so that those filter fields come with default values when the page is opened.

/src/pages/posts/list.tsx
import { getDefaultFilter } from "@pankod/refine-core";
import {
List,
Table,
Radio,
FilterDropdown,
TagField,
useTable,
getDefaultSortOrder,
} from "@pankod/refine-antd";

export const PostList: React.FC = () => {
const { tableProps, sorter, filters } = useTable<IPost>({
initialSorter: [
{
field: "title",
order: "asc",
},
],
initialFilter: [
{
field: "status",
operator: "eq",
value: "draft",
},
],
});

return (
<List>
<Table {...tableProps} rowKey="id">
<Table.Column dataIndex="id" title="ID" sorter />
<Table.Column
dataIndex="title"
title="Title"
sorter={{ multiple: 2 }}
defaultSortOrder={getDefaultSortOrder("title", sorter)}
/>
<Table.Column
dataIndex="content"
title="Content"
sorter={{ multiple: 1 }}
/>
<Table.Column
dataIndex="status"
title="Status"
render={(value) => <TagField value={value} />}
filterDropdown={(props) => (
<FilterDropdown {...props}>
<Radio.Group>
<Radio value="published">Published</Radio>
<Radio value="draft">Draft</Radio>
<Radio value="rejected">Rejected</Radio>
</Radio.Group>
</FilterDropdown>
)}
defaultFilteredValue={getDefaultFilter("status", filters)}
/>
</Table>
</List>
);
};
tip

Filters we give to initialFilter are default filters. In order to prevent filters from being changed, permanentFilter must be used instead of initialFilter.

API

Properties

KeyDescriptionTypeDefault
resourceThe resource to use for table datastring | undefinedResource name that it reads from the url
permanentFilterDefault and unchangeable filterCrudFilters[]
permanentSorterDefault and unchangeable sorter stateCrudSorting[]
initialCurrentInitial page indexnumber1
initialPageSizeNumber of records shown per initial number of pagesnumber10
initialSorterInitial sortingCrudSorting
initialFilterInitial filteringCrudFilters
syncWithLocationSortings, filters, page index and records shown per page are tracked by browser historybooleanValue set in Refine. If a custom resource is given, it will be false
onSearchWhen the search form is submitted, it creates the 'CrudFilters' object. Refer to search form to learn how to create a search formFunction
queryOptionsreact-query's useQuery options UseQueryOptions<
{ data: TData[]; },
TError>
metaDataMetadata query for dataProviderMetaDataQuery{}
liveModeWhether to update data automatically ("auto") or not ("manual") if a related live event is received. The "off" value is used to avoid creating a subscription."auto" | "manual" | "off""off"
liveParamsParams to pass to liveProvider's subscribe method if liveMode is enabled.{ ids?: string[]; [key: string]: any; }undefined
onLiveEventCallback to handle all related live events of this hook.(event: LiveEvent) => voidundefined

Type Parameters

PropertyDesriptionTypeDefault
TDataResult data of the query. Extends BaseRecordBaseRecordBaseRecord
TErrorCustom error object that extends HttpErrorHttpErrorHttpError
TSearchVariablesValues for search params{}

Return values

PropertyDescriptionType
searchFormPropsAnt Design <Form> propsFormProps<TSearchVariables>
tablePropsAnt Design <Table> propsTableProps<TData>
tableQueryResultResult of the react-query's useQueryQueryObserverResult<{
data: TData[];
total: number; },
TError>
sorterCurrent sorting stateCrudSorting
filtersCurrent filters stateCrudFilters

Live Codesandbox Example