A server side external sorting and filtering example #2033
Replies: 14 comments 17 replies
-
Hey, I'm looking for this too! |
Beta Was this translation helpful? Give feedback.
-
Same here - anyone had any joy? If I watch the table filters state in my useEffect hook and pass it to my fetchData callback I just get an infinite loop. Also there isn't an equivalent 'manualFilter' of 'manualPagination' so I don't think it's implemented that way here. |
Beta Was this translation helpful? Give feedback.
-
const {
state: { sortBy }
} = useTable(
{
columns,
data,
manualSortBy: true
},
useSortBy
)
React.useEffect(() => {
fetchData({ sortBy })
}, [fetchData, sortBy]) Almost all plugins have a 'manual' property to build a controlled table. |
Beta Was this translation helpful? Give feedback.
-
I was able to do server-side Global filtering. In essence I did not use any of the plugins that |
Beta Was this translation helpful? Give feedback.
-
I myself was struggling with implementing a server-side sorting (data were a query to postgres) and came up with a solution that works perfectly but needs some writing. In my case react-table is a reusable component, written in .tsx .
export function Table({
columns,
data,
onHeaderClick
}: {
columns: Array<Column>;
data: Array<object>;
onHeaderClick: Function;
}) Setting manualSort is also crucial in this case: const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } = useTable(
{
columns,
data,
manualSortBy: true
},
useSortBy
); As well as setting the table UI itself for sorting: <th {...column.getHeaderProps(column.getSortByToggleProps())}>
<th
{...column.getHeaderProps(column.getSortByToggleProps())}
onClick={() => onHeaderClick(column)}
>
<div>
<span>{column.render('Header')}</span>
<span>
{column.sortDirection === 'ASC' ? (
<ArrowDropUp />
) : column.sortDirection === 'DESC' ? (
<ArrowDropDown />
) : null}
</span>
</div>
</th> Property sortDirection is custom and is a part of columns array (more in next steps).
<Table
columns={columns}
data={data}
onHeaderClick={columnHeaderClick}
/> Nextly, an additional useState necessary for the sort to work was added: const [sort, setSort] = useState({ sortDirection: 'none', accessor: 'some_accessor' }); Now, the columns array which is usually passed to the table, now has objects with extra property sortDirection, eg. : {
Header: 'ID,
accessor: 'client_id',
sortType: 'basic',
sortDirection: sort.accessor === 'client_id' ? sort.direction : 'none'
} Object sort being held in state has a property named accessor which value may only be one of the column id's. Now, the final step was writing the columnHeaderClick async function that takes care of changing the sort direction on the table as well as fetching sorted data and updating the table: const columnHeaderClick = async (column: any) => {
switch (column.sortDirection) {
case 'none':
setSort({ direction: 'ASC', accessor: column.id });
const desc = await getClients( 'ASC', column.id );
setData(desc);
break;
case 'ASC':
setSort({ direction: 'DESC', accessor: column.id });
const asc = await getClients('DESC', column.id);
setData(asc);
break;
case 'DESC':
setSort({ direction: 'none', accessor: column.id });
const newData = await getClients('none', column.id);
setData(newData);
break;
}
}; And VOILA ! The table now has server side sorting and 'arrows' on the header behaving as expected :) Hope that helps ;) |
Beta Was this translation helpful? Give feedback.
-
In my case table is also separate component in which I pass dictionary of filter function like this type FilterFunctionDict<T extends Record<string, unknown>> = Record<
IdType<T>,
(value?: FilterValue) => Promise<void> | void
>;
const filterFunctions = useMemo<FilterFunctionDict<User>>(
() => ({
created: (filterValue) =>
setFilter((filter) =>
filterValue
? { ...filter, createdFrom: filterValue[0], createdTo: filterValue[1] }
: { ...filter, createdFrom: undefined, createdTo: undefined }
),
privacyNotes: (filterValue) =>
setFilter((filter) => ({ ...filter, privacyNotes: filterValue ? IncludeFlag.YES : IncludeFlag.ALL })),
}),
[]
); and then trigger these function directly using state reducer stateReducer: (newState, action, prevState) => {
if (action.type === 'setAllFilters' && !action.filters.length) {
Object.values(filterFunctions).forEach((fn) => fn());
} else if (action.type === 'setFilter') {
filterFunctions[action.columnId] && filterFunctions[action.columnId](action.filterValue);
}
return newState;
}, |
Beta Was this translation helpful? Give feedback.
-
Might be something more specific to my use case, but using @fnn 's solution only worked partially for me. The reason was that react-table only add's an However, the const {
state: { sortBy }
} = useTable(
{
columns,
data,
manualSortBy: true
defaultCanSort: true
},
useSortBy
) Or by specifically setting the const column = [
{
Header: "Organization",
accessor: "organization",
canSort: true
},
] After that, I was finally able to trigger an onClick and listen for sortBy state updates. (Dropping my 2 cents here as it didn't work for me otherwhise) |
Beta Was this translation helpful? Give feedback.
-
Any updates here for managing to get server-side global filtering (search) working? The gist mentioned above appears to no longer exist. |
Beta Was this translation helpful? Give feedback.
-
Hey guys. I tired the following for the server side pagination and filtering. Not sure how good the solution is. Hope this helps someone |
Beta Was this translation helpful? Give feedback.
-
we really need this good example asap 🙏 |
Beta Was this translation helpful? Give feedback.
-
Here is an example that I just made today. I hope it can be useful for you. Firstly, we need to set Check my example on Codesanbox Or you can also check the code below. I make it as simple as I can to reduce the complexity. import React from "react";
import { useTable, useSortBy } from "react-table";
import { fetchUserList } from "./utils";
export default function App() {
const [data, setData] = React.useState([]);
const [isLoading, setLoading] = React.useState(false);
const columns = React.useMemo(
() => [
{
Header: "Name",
accessor: "fullName"
},
{
Header: "Age",
accessor: "age"
},
{
Header: "Status",
accessor: "status"
}
],
[]
);
const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
prepareRow,
// We need to get 'sortBy' from the table state, then use it as an argument to fetch new data
state: { sortBy }
} = useTable(
{
columns,
data,
// we need to tell react-table that we will handle sorting manually
manualSortBy: true
},
useSortBy
);
React.useEffect(() => {
setData([]);
setLoading(true);
fetchUserList({ sortBy })
.then((response) => {
setData(response);
})
.catch((err) => {
console.log(err);
})
.finally(() => {
setLoading(false);
});
}, [sortBy]);
return (
<>
<table {...getTableProps()}>
<thead>
{headerGroups.map((headerGroup) => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map((column) => (
// Add the sorting props to control sorting. For this example
// we can add them into the header props
<th {...column.getHeaderProps(column.getSortByToggleProps())}>
{column.render("Header")}
{/* Add a sort direction indicator */}
<span>
{column.isSorted
? column.isSortedDesc
? " 🔽"
: " 🔼"
: ""}
</span>
</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{isLoading && <span>Loading..</span>}
{rows.map((row, i) => {
prepareRow(row);
return (
<tr {...row.getRowProps()}>
{row.cells.map((cell) => {
return (
<td {...cell.getCellProps()}>{cell.render("Cell")}</td>
);
})}
</tr>
);
})}
</tbody>
</table>
</>
);
} |
Beta Was this translation helpful? Give feedback.
-
Hi everyone. I have gone through everyone's comments here. I can't seem to find a solution for my issue. So basically I set manual prop to true because I was doing a server side pagination but then I want react to still handle the sorting for me. Any idea on how to achieve this please ? Here is a SO question for this. Thanks. |
Beta Was this translation helpful? Give feedback.
-
am i the only one thinking how come no one has used react-query with this? 🤣 |
Beta Was this translation helpful? Give feedback.
-
I almost have a solution, but is there a way to stop the filter inputs from losing focus? It seems like the table's headerGroups are unmounted and re rendering from scratch each time new data is fetched and passed to React Table v7 via the columns prop. |
Beta Was this translation helpful? Give feedback.
-
It would be great if we could have an example of server-side external sorting and filtering example
Beta Was this translation helpful? Give feedback.
All reactions