react-table#UseTableOptions TypeScript Examples

The following examples show how to use react-table#UseTableOptions. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: Table.tsx    From frontegg-react with MIT License 4 votes vote down vote up
Table: FC<TableProps> = <T extends object>(props: TableProps<T>) => {
  const classes = useStyles();
  const tableRef = useRef<HTMLTableElement>(null);
  const firstRender = useRef<boolean>(true);
  const columns = useMemo(() => {
    const columns = props.columns.map(
      ({ sortable, Filter, Header, ...rest }) =>
        ({
          ...rest,
          disableSortBy: !sortable,
          disableFilters: !Filter,
          Filter,
          Header: Header ?? <div style={{ minWidth: rest.minWidth, maxWidth: rest.maxWidth }} />,
        } as FeTableColumnOptions<T>)
    );

    if (props.expandable) {
      columns.unshift({
        id: 'fe-expander',
        minWidth: 60,
        maxWidth: '60px' as any,
        Header: <div style={{ minWidth: '1.5rem', maxWidth: '1.5rem' }} />,
        Cell: (cell: Cell<T>) => {
          const row = cell.row as Row<T> & UseExpandedRowProps<T>;
          return (
            <IconButton className={classes.expandIcon} {...row.getToggleRowExpandedProps()}>
              {row.isExpanded ? <KeyboardArrowUpIcon /> : <KeyboardArrowDownIcon />}
            </IconButton>
          );
        },
      });
    }
    if (props.selection) {
      columns.unshift({
        id: 'fe-selection',
        minWidth: 60,
        maxWidth: '60px' as any,
        Cell: (cell: Cell<T>) => {
          const row = cell.row as Row<T> & UseRowSelectRowProps<T>;
          return (
            <Checkbox
              className={classes.checkBox}
              {...row.getToggleRowSelectedProps()}
              checked={row.isSelected}
              onChange={(e) => onRowSelected(row.original, e.target.checked)}
            />
          );
        },
      });
    }
    return columns as Column<T>[];
  }, [props.columns, props.expandable]);

  const tableHooks: PluginHook<T>[] = [useFilters, useSortBy];
  if (props.expandable) {
    tableHooks.push(useExpanded);
  }
  if (props.pagination) {
    tableHooks.push(usePagination);
  }
  if (props.selection) {
    tableHooks.push(useRowSelect);
  }
  tableHooks.push(useFlexLayout);

  const {
    getTableProps,
    getTableBodyProps,
    headerGroups,
    rows,
    prepareRow,
    state,

    // The page controls ;)
    page,
    // canPreviousPage,
    // canNextPage,
    pageOptions,
    pageCount,
    gotoPage,
    nextPage,
    previousPage,
    // setPageSize,

    // select props
    toggleAllRowsSelected,
    isAllRowsSelected,
    selectedFlatRows,
    toggleRowSelected,
  } = useTable(
    {
      columns,
      data: props.data,
      getRowId: (row: any) => row[props.rowKey],
      manualSortBy: !!props.onSortChange,
      manualFilters: !!props.onFilterChange,
      manualPagination: !!props.onPageChange,
      manualRowSelectedKey: props.rowKey,
      pageCount: !!props.onPageChange ? props.pageCount : undefined,
      autoResetPage: !props.onPageChange,
      useControlledState: (state1: any) => {
        return {
          ...state1,
          sortBy: props.sortBy ?? state1.sortBy,
          filters: props.filters ?? state1.filters,
          selectedRowIds: props.selectedRowIds ?? state1.selectedRowIds,
        } as TableState<T> & UseFiltersState<T> & UseSortByState<T> & UseRowSelectState<T>;
      },
      expandSubRows: false,
      initialState: {
        pageIndex: 0,
        pageSize: props.pageSize ?? 0,
        selectedRowIds: props.selectedRowIds || {},
      },
    } as UseTableOptions<T> &
      UseFiltersOptions<T> &
      UseSortByOptions<T> &
      UseExpandedOptions<T> &
      UseRowSelectOptions<T> &
      UsePaginationOptions<T>,
    ...tableHooks
  ) as TableInstance<T> & UseTableInstanceProps<T> & UsePaginationInstanceProps<T> & UseRowSelectInstanceProps<T>;

  if (props.expandable && !props.renderExpandedComponent) {
    throw Error('FeTable: you must provide renderExpandedComponent property if the table is expandable');
  }
  if (props.hasOwnProperty('sortBy') && !props.onSortChange) {
    throw Error('FeTable: you must provide onSortChange property if sortBy is controlled');
  }
  if (props.hasOwnProperty('filters') && !props.onFilterChange) {
    throw Error('FeTable: you must provide onFilterChange property if filters is controlled');
  }
  if (props.hasOwnProperty('pagination') && !props.pageSize) {
    throw Error('FeTable: you must provide pageSize property if pagination enabled');
  }
  if (props.hasOwnProperty('onPageChange') && !props.pageCount) {
    throw Error('FeTable: you must provide pageCount property if onPageChange is controlled');
  }

  const tableState = state as UseSortByState<T> & UseFiltersState<T> & UsePaginationState<T> & UseRowSelectState<T>;

  const onSortChange = useCallback(
    (column: FeTableColumnProps<T>) => {
      if (props.hasOwnProperty('sortBy')) {
        const sortBy = props.isMultiSort ? tableState.sortBy.filter(({ id }) => id !== column.id) : [];
        if (!column.isSorted) {
          sortBy.push({ id: column.id, desc: false });
        } else if (!column.isSortedDesc) {
          sortBy.push({ id: column.id, desc: true });
        }
        props.onSortChange?.(sortBy);
      } else {
        if (column.isSorted && column.isSortedDesc) {
          column.clearSortBy();
        } else {
          column.toggleSortBy(column.isSorted, props.isMultiSort ?? false);
        }
      }
    },
    [props.onSortChange]
  );

  const onFilterChange = useCallback(
    (column: FeTableColumnProps<T>, filterValue?: any) => {
      if (props.hasOwnProperty('filters')) {
        const filters = tableState.filters.filter(({ id }) => id !== column.id);
        if (filterValue != null) {
          filters.push({ id: column.id, value: filterValue });
        }
        props.onFilterChange?.(filters);
      } else {
        column.setFilter(filterValue);
      }
    },
    [props.onFilterChange, tableState]
  );

  const onToggleAllRowsSelected = useCallback(
    (value: boolean) => {
      if (props.hasOwnProperty('selectedRowIds')) {
        const selectedIds = props.data.reduce((p, n: any) => ({ ...p, [n[props.rowKey]]: true }), {});
        props.onRowSelected?.(value ? selectedIds : {});
      } else {
        toggleAllRowsSelected(value);
      }
    },
    [props.onRowSelected]
  );

  const onRowSelected = useCallback(
    (row: any, value: boolean) => {
      const id = row[props.rowKey];
      if (props.hasOwnProperty('selectedRowIds')) {
        const newSelectedRows: any = { ...props.selectedRowIds };
        if (value) {
          newSelectedRows[id] = true;
        } else {
          delete newSelectedRows[id];
        }
        props.onRowSelected?.(newSelectedRows);
      } else {
        toggleRowSelected(id, value);
      }
    },
    [props.onRowSelected]
  );

  const handleOnPageChange = useCallback(() => {
    if (pagination === 'pages') {
      tableRef.current?.scroll?.({ top: 0, left: 0, behavior: 'smooth' });
    }
    props.onPageChange?.(tableState.pageSize, tableState.pageIndex);
  }, [tableState.pageIndex]);

  useEffect(() => {
    !props.hasOwnProperty('sortBy') && props.onSortChange?.(tableState.sortBy);
  }, [props.sortBy, tableState.sortBy]);

  useEffect(() => {
    !props.hasOwnProperty('filters') && props.onFilterChange?.(tableState.filters);
  }, [props.filters, tableState.filters]);

  useEffect(() => {
    firstRender.current ? (firstRender.current = false) : handleOnPageChange();
  }, [tableState.pageIndex]);

  useEffect(() => {
    !props.hasOwnProperty('selectedRowIds') && props.onRowSelected?.(tableState.selectedRowIds as any);
  }, [tableState.selectedRowIds]);

  const onPageChangeHandler = (page: number) => {
    if (page > tableState.pageIndex) {
      nextPage();
    } else {
      previousPage();
    }
  };

  const { className, loading, pagination, totalData, pageSize } = props;

  return (
    <Paper ref={tableRef} className={classes.paper}>
      <MaUTable className={classNames(classes.table, className)} {...getTableProps()}>
        <TableHead
          headerGroups={headerGroups}
          onSortChange={onSortChange}
          onFilterChange={onFilterChange}
          toggleAllRowsSelected={onToggleAllRowsSelected}
          isAllRowsSelected={isAllRowsSelected}
          selectedFlatRows={selectedFlatRows}
        />
        <TableBody
          pageSize={pageSize}
          pagination={pagination}
          getTableBodyProps={getTableBodyProps}
          prepareRow={prepareRow}
          loading={loading}
          rows={(pagination ? page : rows) as (Row<T> & UseExpandedRowProps<T>)[]}
          renderExpandedComponent={props.renderExpandedComponent}
          onInfiniteScroll={handleOnPageChange}
        />
      </MaUTable>

      {loading && pagination === 'pages' && rows.length > 0 && <Loader center size={24} />}
      {pagination === 'pages' && (
        <TablePagination
          className={classes.footer}
          rowsPerPageOptions={[]}
          component='div'
          count={totalData || rows.length}
          rowsPerPage={tableState.pageSize}
          page={tableState.pageIndex}
          onChangePage={(e, page) => onPageChangeHandler(page)}
          ActionsComponent={(props) => (
            <TablePaginationActions {...props} gotoPage={gotoPage} pageOptions={pageOptions} />
          )}
        />
      )}
    </Paper>
  );
}
Example #2
Source File: Table.tsx    From opensaas with MIT License 4 votes vote down vote up
Table: React.FC<TableProps> = <T extends object>(props: TableProps<T>) => {
  const {
    expandable,
    selection,
    pagination,
    sortBy,
    pageCount,
    data,
    selectedRowIds,
    pageSize,
    rowKey,
    loading,
    isMultiSort,
    renderExpandedComponent,
    onPageChange,
    filters: propsFilters,
    onSortChange: propsOnSortChange,
    onRowSelected: propsOnRowSelected,
    onFilterChange: propsOnFilterChange,
    columns: propsColumns,
  } = props;
  const classes = useStyles();
  const tableRef = useRef<HTMLTableElement>(null);

  const hasSortBy = props.hasOwnProperty('sortBy');
  const hasFilters = props.hasOwnProperty('filters');
  const hasPagination = props.hasOwnProperty('pagination');
  const hasOnPageChange = props.hasOwnProperty('onPageChange');
  const hasSelectedRowIds = props.hasOwnProperty('selectedRowIds');

  const onRowSelected = useCallback(
    (row: UseRowSelectRowProps<T> & Row<T> & UseTableRowProps<T>, value: boolean) => {
      const id = (row.original as any)[rowKey];
      if (hasSelectedRowIds) {
        const newSelectedRows: any = { ...selectedRowIds };
        if (value) {
          newSelectedRows[id] = true;
        } else {
          delete newSelectedRows[id];
        }
        propsOnRowSelected?.(newSelectedRows);
      } else {
        row.toggleRowSelected(value);
      }
    },
    [hasSelectedRowIds, rowKey, selectedRowIds, propsOnRowSelected],
  );

  const columns = useMemo(() => {
    const columns = propsColumns.map(
      ({ sortable, Filter, Header, ...rest }) =>
        ({
          ...rest,
          disableSortBy: !sortable,
          disableFilters: !Filter,
          Filter,
          Header: Header ?? <div style={{ minWidth: rest.minWidth, maxWidth: rest.maxWidth }} />,
        } as TableColumnOptions<T>),
    );

    if (expandable) {
      columns.unshift({
        id: 'expander',
        minWidth: 60,
        maxWidth: '60px' as any,
        Cell: (cell: UseTableCellProps<T>) => {
          const row = cell.row as Row<T> & UseExpandedRowProps<T>;
          return (
            <IconButton className={classes.expandIcon} {...row.getToggleRowExpandedProps()}>
              {row.isExpanded ? <KeyboardArrowUpIcon /> : <KeyboardArrowDownIcon />}
            </IconButton>
          );
        },
      });
    }
    if (selection) {
      columns.unshift({
        id: 'selection',
        minWidth: 60,
        maxWidth: '60px' as any,
        Cell: (cell: UseTableCellProps<T>) => {
          const row = cell.row as UseRowSelectRowProps<T> & Row<T> & UseTableRowProps<T>;
          return (
            <Checkbox
              className={classes.checkBox}
              {...row.getToggleRowSelectedProps()}
              checked={row.isSelected}
              onChange={(e) => onRowSelected(row, e.target.checked)}
            />
          );
        },
      });
    }
    return columns as Column<T>[];
  }, [propsColumns, expandable, classes, selection, onRowSelected]);

  const tableHooks: PluginHook<T>[] = [useFilters, useSortBy];
  if (expandable) {
    tableHooks.push(useExpanded);
  }
  if (pagination) {
    tableHooks.push(usePagination);
  }
  if (selection) {
    tableHooks.push(useRowSelect);
  }
  tableHooks.push(useFlexLayout);

  const {
    getTableProps,
    getTableBodyProps,
    headerGroups,
    rows,
    prepareRow,
    state,
    page,
    pageOptions,
    gotoPage,
    nextPage,
    previousPage,
    toggleAllRowsSelected,
    isAllRowsSelected,
    selectedFlatRows,
  } = useTable(
    {
      columns,
      data,
      getRowId: (row: any) => row[rowKey],
      manualSortBy: !!propsOnSortChange,
      manualFilters: !!propsOnFilterChange,
      manualPagination: !!onPageChange,
      manualRowSelectedKey: rowKey,
      pageCount: pageCount ?? 0,
      useControlledState: (state1: any) =>
        ({
          ...state1,
          sortBy: sortBy ?? state1.sortBy,
          filters: propsFilters ?? state1.filters,
          selectedRowIds: selectedRowIds ?? state1.selectedRowIds,
        } as TableState<T> & UseFiltersState<T> & UseSortByState<T> & UseRowSelectState<T>),
      expandSubRows: false,
      initialState: {
        pageIndex: 0,
        pageSize: pageSize ?? 0,
        selectedRowIds: selectedRowIds || {},
      },
    } as UseTableOptions<T> &
      UseFiltersOptions<T> &
      UseSortByOptions<T> &
      UseExpandedOptions<T> &
      UseRowSelectOptions<T> &
      UsePaginationOptions<T>,
    ...tableHooks,
  ) as TableInstance<T> & UseTableInstanceProps<T> & UsePaginationInstanceProps<T> & UseRowSelectInstanceProps<T>;

  if (expandable && !renderExpandedComponent) {
    throw Error('Table: you must provide renderExpandedComponent property if the table is expandable');
  }
  if (hasSortBy && !propsOnSortChange) {
    throw Error('Table: you must provide onSortChange property if sortBy is controlled');
  }
  if (hasFilters && !propsOnFilterChange) {
    throw Error('Table: you must provide onFilterChange property if filters is controlled');
  }
  if (hasPagination && !pageSize) {
    throw Error('Table: you must provide pageSize property if pagination enabled');
  }
  if (hasOnPageChange && !pageCount) {
    throw Error('Table: you must provide pageCount property if onPageChange is controlled');
  }

  const tableState = state as UseSortByState<T> & UseFiltersState<T> & UsePaginationState<T> & UseRowSelectState<T>;

  const onSortChange = useCallback(
    (column: TableColumnProps<T>) => {
      if (hasSortBy) {
        const sortBy = isMultiSort ? tableState.sortBy.filter(({ id }) => id !== column.id) : [];
        if (!column.isSorted) {
          sortBy.push({ id: column.id, desc: false });
        } else if (!column.isSortedDesc) {
          sortBy.push({ id: column.id, desc: true });
        }
        propsOnSortChange?.(sortBy);
      } else {
        if (column.isSorted && column.isSortedDesc) {
          column.clearSortBy();
        } else {
          column.toggleSortBy(column.isSorted, isMultiSort ?? false);
        }
      }
    },
    [hasSortBy, isMultiSort, tableState.sortBy, propsOnSortChange],
  );

  const onFilterChange = useCallback(
    (column: TableColumnProps<T>, filterValue?: any) => {
      if (hasFilters) {
        const filters = tableState.filters.filter(({ id }) => id !== column.id);
        if (filterValue != null) {
          filters.push({ id: column.id, value: filterValue });
        }
        propsOnFilterChange?.(filters);
      } else {
        column.setFilter(filterValue);
      }
    },
    [propsOnFilterChange, hasFilters, tableState.filters],
  );

  const onToggleAllRowsSelected = useCallback(
    (value: boolean) => {
      if (hasSelectedRowIds) {
        const selectedIds = data.reduce((p, n: any) => ({ ...p, [n[rowKey]]: true }), {});
        propsOnRowSelected?.(value ? selectedIds : {});
      } else {
        toggleAllRowsSelected(value);
      }
    },
    [hasSelectedRowIds, data, rowKey, propsOnRowSelected, toggleAllRowsSelected],
  );

  useEffect(() => {
    if (!hasSortBy) propsOnSortChange?.(tableState.sortBy);
  }, [hasSortBy, propsOnSortChange, tableState.sortBy]);

  useEffect(() => {
    if (!hasFilters) propsOnFilterChange?.(tableState.filters);
  }, [hasFilters, propsOnFilterChange, tableState.filters]);

  useEffect(() => {
    tableRef.current?.querySelector('.table-tbody')?.scroll?.({ top: 0, left: 0, behavior: 'smooth' });
    onPageChange?.(tableState.pageSize, tableState.pageIndex);
  }, [onPageChange, tableState.pageSize, tableState.pageIndex]);

  useEffect(() => {
    if (!hasSelectedRowIds) propsOnRowSelected?.(tableState.selectedRowIds as any);
  }, [hasSelectedRowIds, propsOnRowSelected, tableState.selectedRowIds]);

  const onPageChangeHandler = (page: number) => {
    if (page > tableState.pageIndex) {
      nextPage();
    } else {
      previousPage();
    }
  };

  return (
    <Paper className={classes.paper}>
      <MaterialUITable className={classes.table} ref={tableRef} {...getTableProps()}>
        <TableHead
          headerGroups={headerGroups}
          onSortChange={onSortChange}
          onFilterChange={onFilterChange}
          toggleAllRowsSelected={onToggleAllRowsSelected}
          isAllRowsSelected={isAllRowsSelected}
          selectedFlatRows={selectedFlatRows}
        />
        <TableBody
          getTableBodyProps={getTableBodyProps}
          prepareRow={prepareRow}
          loading={loading}
          rows={(pagination ? page : rows) as (Row<T> & UseExpandedRowProps<T>)[]}
          renderExpandedComponent={renderExpandedComponent}
        />
      </MaterialUITable>
      {pagination === 'pages' && (
        <TablePagination
          className={classes.footer}
          rowsPerPageOptions={[]}
          component='div'
          count={rows.length}
          rowsPerPage={tableState.pageSize}
          page={tableState.pageIndex}
          onChangePage={(e, page) => onPageChangeHandler(page)}
          ActionsComponent={(props) => (
            <TablePaginationActions {...props} gotoPage={gotoPage} pageOptions={pageOptions} />
          )}
        />
      )}
    </Paper>
  );
}