Frontend Hooks (useTableData)
Relevant source files
The following files were used as context for generating this wiki page:
The frontend hooks in the better-tables project provide the reactive glue between the core state management, database adapters, and the UI layer. The primary hook, useTableData, orchestrates data fetching lifecycles, ensuring that table content remains synchronized with filters, pagination, and sorting state while preventing common issues like race conditions and memory leaks.
These hooks are designed to be used within React components to manage complex table behaviors such as keyboard navigation, URL state synchronization, and optimized data retrieval. By utilizing a central table store, the hooks maintain a consistent state across different parts of the UI, such as the table body, filter bars, and pagination controls.
Sources: packages/ui/src/hooks/use-table-data.ts, plans/010-ui-hooks-correctness.md
Core Data Fetching: useTableData
The useTableData hook is responsible for fetching data from a provided adapter and managing the loading, error, and data states. It reacts to changes in filters, pagination, and params to trigger new requests.
Data Flow and Lifecycle
The hook utilizes useCallback to memoize the fetchData function and an useEffect to trigger it. To prevent unbounded refetch loops, stable default constants are used for optional parameters like filters and params.
The flow ensures that only the most recent request's result is applied to the state, effectively handling rapid filter changes.
Sources: packages/ui/src/hooks/use-table-data.ts:84-164, plans/034-usetabledata-loop-and-date-render.md:40-49
Request Synchronization and Safety
To handle asynchronous race conditions, the hook implements a monotonic request ID and AbortController management.
| Feature | Implementation | Purpose |
|---|---|---|
| Abort Signaling | AbortController in useRef | Cancels in-flight requests on unmount or new fetch start. |
| Sequence Guard | requestIdRef (monotonic counter) | Ensures out-of-order completions do not render stale data. |
| Stable Defaults | EMPTY_FILTERS / EMPTY_PARAMS | Prevents literal {} or [] from breaking memoization. |
| Fetch Signal | FetchDataParams.signal | Passes the abort signal directly to the database adapter. |
Sources: packages/ui/src/hooks/use-table-data.ts:10-25, plans/010-ui-hooks-correctness.md:95-120
State Synchronization: useTableUrlSync
The useTableUrlSync hook facilitates deep-linking by synchronizing the table's internal state (filters, sorting, pagination) with the browser's URL query parameters.
Hydration and Debouncing
The synchronization logic involves two phases: hydration (reading from URL to store) and synchronization (writing from store to URL). Because URL updates can be frequent, a 150ms debounce is applied to prevent browser history flooding.
Keyboard Navigation: useKeyboardNavigation
For accessibility and power-user efficiency, the useKeyboardNavigation hook manages focus and selection within the table grid using standard keyboard shortcuts.
Supported Keys and Actions
The hook listens for specific KeyboardEvent keys to move focus or manipulate row selection.
- Arrow Keys: Move focus between cells (Up, Down, Left, Right).
- Space / Enter: Toggle row selection for the focused row.
- Home / End: Jump to the first or last cell in a row.
- PageUp / PageDown: Move focus by a larger step (often mapped to pagination or virtualization chunks).
Sources: packages/ui/src/hooks/use-keyboard-navigation.ts
Table Store Management
The useTableStore hook provides access to the underlying TableStateManager for a specific table ID. This store acts as the single source of truth for all frontend hooks.
Summary of Configuration Options
The primary configuration for data fetching via useTableData is defined by the UseTableDataOptions interface.
| Option | Type | Description |
|---|---|---|
adapter | TableAdapter | The database adapter (e.g., Drizzle or HTTP) used to fetch data. |
filters | FilterState[] | Array of active filters; defaults to EMPTY_FILTERS. |
pagination | PaginationState | Current page and limit configuration. |
params | Record<string, unknown> | Custom parameters passed to the adapter. |
enabled | boolean | Flag to pause/resume data fetching. |
Sources: packages/ui/src/hooks/use-table-data.ts:84-90, plans/034-usetabledata-loop-and-date-render.md:40-49
In conclusion, the frontend hooks, centered around useTableData, provide a robust framework for managing data-intensive tables in React. By addressing lifecycle hazards such as race conditions and providing integrated URL synchronization, these hooks enable developers to build performant and accessible data grids with minimal boilerplate.