T
TanStack2y ago
adverse-sapphire

Integrating reusable tanstack table

I figured I'd ask this since I don't think it's been discussed. I have a reusable data table component (shadcn data-table). I think this works as expected for syncing the search params and path params with the data table state However I'm not sure if this is the best approach so figured I'd leave this up here I do notice that using const navigate = useNavigate() returns all the search params from the router, so I have to make sure to use the same common search params across multiple routes that use this data table. Not sure if there's a way to specify the Working on this in real time... One issue is when using the back button, it doesnt restore the table state. so i think i need to instead refer to the search params and update the table state from it rather than the component state?
No description
8 Replies
adverse-sapphire
adverse-sapphireOP2y ago
looks like type safety is lost here. but im trying to use strict: false since this could be rendered on different routes.
No description
fair-rose
fair-rose2y ago
Not super related to the search, but a suggestion for pagination state. Keep only one source of truth and have it be the URL. You can kill the useEffect syncing and instead just make the table fully controlled by the URL search params. https://tanstack.com/table/v8/docs/examples/react/fully-controlled
React Table Fully Controlled Example | TanStack Table Docs
An example showing how to implement Fully Controlled in React Table
adverse-sapphire
adverse-sapphireOP2y ago
Thanks ill take a look. Any thoughts if I'm accessing the searchParams incorrectly in my 2nd screenshot? maybe i send the searchParams as a prop higher in the tree and read those values, but i can still use navigate to set the searchParams where i need to?
fair-rose
fair-rose2y ago
Ya, could always just have a callback where you handle passing it to the local searchParams instance vs. embedding it? Would allow for re-using the table from the URL vs. local state.
adverse-sapphire
adverse-sapphireOP2y ago
Do you have a quick code sample of what you’re thinking?
fair-rose
fair-rose2y ago
Something along these lines
<Table
data={data}
onPagination={({ page, per }) => {
navigate({ search: {{ page, per }}) })
}}
/>
<Table
data={data}
onPagination={({ page, per }) => {
navigate({ search: {{ page, per }}) })
}}
/>
Not sure if it would be pagination only, but could be renamed to onStateChange if it includes more. Then if it was local, you could replace navigate with a setState.
adverse-sapphire
adverse-sapphireOP2y ago
Thanks. So i think I was able to get it working. we'll see. i'm not super confident working with tanstack table. Hopefully soon someone can make an example with it
// Pagination button example
<Button
variant='outline'
className='w-8 h-8 p-0'
onClick={() => {
if (table.getCanPreviousPage()) {
navigate({
search: {
...searchParams,
page: page - 1,
},
params: params.teamId,
})
table.previousPage()
}
}}
disabled={!table.getCanPreviousPage()}
>
<span className='sr-only'>Go to previous page</span>
<ChevronLeft className='w-4 h-4' />
</Button>
// Pagination button example
<Button
variant='outline'
className='w-8 h-8 p-0'
onClick={() => {
if (table.getCanPreviousPage()) {
navigate({
search: {
...searchParams,
page: page - 1,
},
params: params.teamId,
})
table.previousPage()
}
}}
disabled={!table.getCanPreviousPage()}
>
<span className='sr-only'>Go to previous page</span>
<ChevronLeft className='w-4 h-4' />
</Button>
No description
fair-rose
fair-rose2y ago
This is what I do with Tanstack Table. I fully commit the pagination state to the URL search params. So it comes out like this. Use the links to to view the actual code, whats below are more simplified.
/**
* Use the Tanstack table PaginationState type to map the values before passing it into the table
* @link https://github.com/SeanCassiere/nv-rental-clone/blob/1d469817f509f6fe3b1388630c90956d0317d646/src/pages/search-agreements.tsx#L67-L73
*/
const pagination: PaginationState = {
pageIndex: search.pageNumber === 0 ? 0 : search.pageNumber - 1 // this is because in search I want the page to be shown as 1, but Tanstack table uses indexes starting at 0,
pageSize: size ?? 10,
}

/**
* Create an OnChangeFn for PaginationState and pass it into the reusable data table component.
* @link https://github.com/SeanCassiere/nv-rental-clone/blob/1d469817f509f6fe3b1388630c90956d0317d646/src/pages/search-agreements.tsx#L244-L256
*/
const onPaginationChange = (newPaginationState) => {
navigate({
to: "/agreements",
search: (current) => ({
...current,
page: newPaginationState.pageIndex + 1,
size: newPaginationState.pageSize,
filters: searchFilters,
}),
});
}

/**
* This is how the types for pagination should be passed in
* @link https://github.com/SeanCassiere/nv-rental-clone/blob/1d469817f509f6fe3b1388630c90956d0317d646/src/components/primary-module/table.tsx#L67-L92
*/
interface Props {
pagination: PaginationState;
onPaginationChange: OnChangeFn<PaginationState>;
...
}

/**
* Then pass down the state and the updater fn to the useReactTable hook.
* @link https://github.com/SeanCassiere/nv-rental-clone/blob/1d469817f509f6fe3b1388630c90956d0317d646/src/components/primary-module/table.tsx#L120-L157
*/
/**
* Use the Tanstack table PaginationState type to map the values before passing it into the table
* @link https://github.com/SeanCassiere/nv-rental-clone/blob/1d469817f509f6fe3b1388630c90956d0317d646/src/pages/search-agreements.tsx#L67-L73
*/
const pagination: PaginationState = {
pageIndex: search.pageNumber === 0 ? 0 : search.pageNumber - 1 // this is because in search I want the page to be shown as 1, but Tanstack table uses indexes starting at 0,
pageSize: size ?? 10,
}

/**
* Create an OnChangeFn for PaginationState and pass it into the reusable data table component.
* @link https://github.com/SeanCassiere/nv-rental-clone/blob/1d469817f509f6fe3b1388630c90956d0317d646/src/pages/search-agreements.tsx#L244-L256
*/
const onPaginationChange = (newPaginationState) => {
navigate({
to: "/agreements",
search: (current) => ({
...current,
page: newPaginationState.pageIndex + 1,
size: newPaginationState.pageSize,
filters: searchFilters,
}),
});
}

/**
* This is how the types for pagination should be passed in
* @link https://github.com/SeanCassiere/nv-rental-clone/blob/1d469817f509f6fe3b1388630c90956d0317d646/src/components/primary-module/table.tsx#L67-L92
*/
interface Props {
pagination: PaginationState;
onPaginationChange: OnChangeFn<PaginationState>;
...
}

/**
* Then pass down the state and the updater fn to the useReactTable hook.
* @link https://github.com/SeanCassiere/nv-rental-clone/blob/1d469817f509f6fe3b1388630c90956d0317d646/src/components/primary-module/table.tsx#L120-L157
*/

Did you find this page helpful?