Skip to content

useDataTable

Hook for schema-driven data tables with pagination, sorting, filtering, and selection.

React Native uses the same useDataTable hook from @ybyra/react.

Basic Usage

tsx
import { useDataTable } from '@ybyra/react'
import { Scope } from '@ybyra/core'

function PersonList() {
  const table = useDataTable({
    schema: PersonSchema.provide(),
    scope: Scope.index,
    handlers: personHandlers,
    hooks: personHooks,
    component: componentContract,
    translate: t,
  })

  if (table.loading) return <ActivityIndicator />
  if (table.empty) return <Text>No records found</Text>

  return (
    <View>
      <FlatList
        data={table.rows}
        keyExtractor={(row) => table.getIdentity(row)}
        renderItem={({ item: row }) => (
          <View>
            {table.columns.map((col) => (
              <Text key={col.name}>
                {table.formatValue(col.name, row[col.name], row)}
              </Text>
            ))}
          </View>
        )}
      />

      <View>
        <Button
          title="Previous"
          disabled={table.page <= 1}
          onPress={() => table.setPage(table.page - 1)}
        />
        <Text>Page {table.page} of {table.totalPages}</Text>
        <Button
          title="Next"
          disabled={table.page >= table.totalPages}
          onPress={() => table.setPage(table.page + 1)}
        />
      </View>
    </View>
  )
}

Options

typescript
interface UseDataTableOptions {
  schema: SchemaProvide
  scope: ScopeValue
  handlers?: Record<string, HandlerFn>
  hooks?: SchemaHooks
  context?: Record<string, unknown>
  component: ComponentContract
  pageSize?: number
  translate?: TranslateContract
}
OptionRequiredDescription
schemaYesOutput of SchemaDefinition.provide()
scopeYesCurrent scope (typically Scope.index)
handlersNoAction handlers
hooksNoLifecycle hooks (fetch hooks provide data)
componentYesComponentContract implementation
pageSizeNoItems per page (default varies)
translateNoTranslation function

Return Value

Data

PropertyTypeDescription
rowsRecord<string, unknown>[]Current page data
loadingbooleanTrue while fetching data
emptybooleanTrue if no rows

Columns

PropertyTypeDescription
columnsResolvedColumn[]Visible columns
availableColumnsResolvedColumn[]All available columns
visibleColumnsstring[]Names of visible columns
toggleColumn(name)functionToggle column visibility

Pagination

PropertyTypeDescription
pagenumberCurrent page
limitnumberItems per page
totalnumberTotal record count
totalPagesnumberTotal page count
setPage(page)functionNavigate to page
setLimit(limit)functionChange page size

Sorting

PropertyTypeDescription
sortFieldstring | undefinedCurrent sort field
sortOrder'asc' | 'desc' | undefinedSort direction
setSort(field)functionToggle sort on field

Filtering

PropertyTypeDescription
filtersRecord<string, unknown>Active filters
setFilter(field, value)functionSet a filter value
clearFilters()functionClear all filters

Selection

PropertyTypeDescription
selectedRecord<string, unknown>[]Selected rows
isSelected(record)functionCheck if row is selected
toggleSelect(record)functionToggle row selection
selectAll()functionSelect all rows
clearSelection()functionClear selection

Actions

PropertyTypeDescription
actionsResolvedAction[]Top-level actions (e.g., "Add")
getRowActions(record)functionGet actions for a specific row

Utilities

MethodDescription
reload()Re-fetch current page data
formatValue(name, value, record)Format a cell value using column config
getIdentity(record)Get the identity key for a record

Column Configuration

Fields become table columns when marked with .column():

typescript
text().column()               // basic column
text().column().sortable()    // sortable
text().column().filterable()  // filterable

Fetch Hooks

Table data is loaded through fetch hooks:

typescript
const personHooks = PersonSchema.hooks({
  fetch: {
    [Scope.index]: async ({ params }) => {
      return personService.paginate(params)
    },
  },
})

The params object contains pagination, sorting, and filter state:

typescript
interface PaginateParams {
  page: number
  limit: number
  sort?: string
  order?: 'asc' | 'desc'
  filters?: Record<string, unknown>
}

The hook expects a PaginatedResult:

typescript
interface PaginatedResult<T> {
  data: T[]
  total: number
  page: number
  limit: number
}

ResolvedColumn

typescript
interface ResolvedColumn {
  name: string
  config: FieldConfig
  table: TableConfig
}

Released under the MIT License.