Wener Notes

react-table

约 3 分钟阅读
  • tannerlinsley/react-tableGitHubtannerlinsley/react-tabletannerlinsley/react-table · 基于 Hook 功能强大的 Table 组件 · v8+ 框架无关,不再使用插件模式 · 针对同一个状态,不要 initialState 和 state 都设置 · 不支持 sticky 行列笔记:react-table
    • 基于 Hook 功能强大的 Table 组件
  • v8+ 框架无关,不再使用插件模式
  • 针对同一个状态,不要 initialState 和 state 都设置
  • 不支持 sticky 行列

Note

TypeScript
// 完整空状态
const InitialTableState = {
  columnVisibility: {},
  columnOrder: [],
  columnPinning: {
    left: [],
    right: [],
  },
  columnFilters: [],
  globalFilter: {},
  sorting: [],
  expanded: {},
  grouping: [],
  columnSizing: {},
  columnSizingInfo: {
    startOffset: null,
    startSize: null,
    deltaOffset: null,
    deltaPercentage: null,
    isResizingColumn: false,
    columnSizingStart: [], // [string, number][]
  },
  pagination: {
    pageIndex: 0,
    pageSize: 30,
  },
  rowSelection: {},
} as TableState;

export interface TableState
  extends CoreTableState,
    VisibilityTableState,
    ColumnOrderTableState,
    ColumnPinningTableState,
    RowPinningTableState,
    ColumnFiltersTableState,
    GlobalFilterTableState,
    SortingTableState,
    ExpandedTableState,
    GroupingTableState,
    ColumnSizingTableState,
    PaginationTableState,
    RowSelectionTableState {
  columnVisibility: Record<string, boolean>;
  columnOrder: string[];
  columnPinning: {
    left?: string[];
    right?: string[];
  };
  rowPinning: {
    top?: string[];
    bottom?: string[];
  };
  columnFilters: Array<{
    id: string;
    value: unknown;
  }>;
  globalFilter: any;
  sorting: Array<{
    id: string;
    desc: boolean;
  }>;
  expanded: true | Record<string, boolean>;
  grouping: string[];
  columnSizing: Record<string, number>;
  columnSizingInfo: {
    // ColumnSizingInfoState
    columnSizingStart: [string, number][];
    deltaOffset: null | number;
    deltaPercentage: null | number;
    isResizingColumn: false | string;
    startOffset: null | number;
    startSize: null | number;
  };
  pagination: {
    pageIndex: number;
    pageSize: number;
  };
  rowSelection: Record<string, boolean>;
}
  • react-table 基于 table-core 提供简单的状态管理
    • 提供 flexRender, useReactTable
  • useReactTable
    • 处理 - state, onStateChange
    • 核心逻辑
      • createTable, 持有 ref
        • 返回的 table 一直不会变
      • 更新 table 状态
        • useState 作为 table 的 state - 初始值为构建后的 initialState
        • onStateChange 为 setState
          • 因此每次 state 变化 useTable 也会 rerender

useTable

  • 需要 memoized 的属性
    • colums, data, getSubRows, getRowId
  • getCoreRowModel
    • (table: Table<TData>) => () => RowModel<TData>
    • 只会调用 1 次
    • memo table.options.data
  • getSubRows?: (originalRow: TData,index: number) => undefined | TData[]
  • getRowId?: (originalRow: TData,index: number,parent?: Row<TData>) => string
    • 默认用 index 作为 id
TSX
export function useReactTable<TData extends RowData>(options: TableOptions<TData>) {
  // 合并选项
  const resolvedOptions: TableOptionsResolved<TData> = {
    state: {}, // Dummy state
    onStateChange: () => {}, // noop
    renderFallbackValue: null,
    ...options,
  };

  // 创建 table
  const [tableRef] = React.useState(() => ({
    current: createTable<TData>(resolvedOptions),
  }));

  // 使用 react 状态
  const [state, setState] = React.useState(() => tableRef.current.initialState);

  // 优先使用用户提供的状态
  tableRef.current.setOptions((prev) => ({
    ...prev,
    ...options,
    state: {
      ...state,
      ...options.state,
    },
    // 维护两边状态
    onStateChange: (updater) => {
      setState(updater);
      options.onStateChange?.(updater);
    },
  }));

  return tableRef.current;
}

插件

TypeScript
export const usePagination = (hooks) => {
  hooks.stateReducers.push(reducer);
  hooks.useInstance.push(useInstance);
};

// 状态处理
function reducer(state, action: { type }, previousState, instance) {
  // 初始化
  if (action.type === actions.init) {
    return {
      pageSize: 10,
      pageIndex: 0,
      ...state,
    };
  }
}

// 会在 hook 中循环调用 - 可以使用 react hook 实现插件状态
// 可添加额外方法到 instance
function useInstance(instance) {}

usePagination

  • 受控分页
    • 对 row 数据进行分页
    • 基于行数计算 pageCount
  • 非受控分页
    • 用于服务端接口场景
    • 提供 pageCount
TypeScript
interface PaginationState {
  pageIndex;
  pageSize;
}

interface PaginationInstance {
  pageCount: number;
  pageOptions: number[];
  page: Row[];

  canPreviousPage: boolean;
  canNextPage: boolean;

  // 操作 - 进行 dispatch
  gotoPage(pageIndex);
  previousPage();
  nextPage();
  setPageSize(pageSize);
}

useTokenPagination

useRowSelect

  • 默认会在 row 上设置 isSelected
TypeScript
interface RowSelectOptions {
  initialState: {
    selectedRowIds: Record<string: boolean> // rowId
  }
  manualRowSelectedKey?:string // 'isSelected'
  autoResetSelectedRows?:bool // true
}


interface RowSelectInstance {
  toggleRowSelected(rowPath: string, set?: boolean): void;

  toggleAllRowsSelected(set?: boolean): void;

  toggleAllPageRowsSelected(set?: boolean): void;

  getToggleAllPageRowsSelectedProps(props): RowSelectProps;

  getToggleAllRowsSelectedProps(props): RowSelectProps;

  isAllRowsSelected: boolean;
  selectedFlatRows: Array<Row>;
}

interface RowSelectProps {
  onChange;
  style: { cursor };
  indeterminate;
  title;
}

interface RowSelectRowProps {
  isSelected: boolean;
  isSomeSelected: boolean;
  toggleRowSelected(set?: boolean);
  getToggleRowSelectedProps(props): RowSelectProps;
}

FAQ

in deeply nested key "" returned undefined

关联信息

反向链接、本文链接的其他页面和外部资料。

反向链接

  • React Awesome
    笔记 · react-table

    专门功能选择专业组件 - Headless 配合 UI 组件达到更为理想的结果 · react-table · react-hook-form · floatingui · 选择样式与组件独立的 UI 库 · tailwindcss+daisyui

References

GitHub8 条
最近更新commit 8321b4aEdit

On this page