hook use table
6/16/2025
import { get } from '@/utils/object';
import { useCallback, useEffect, useRef, useState } from 'react';
 
/* you may need to customize the params */
export interface Params {
  pageNum: number;
  pageSize: number;
  [key: string]: any;
}
 
export interface Options<T> {
  defaultParams?: Partial<T>;
  manual?: boolean;
  paths?: {
    data?: string;
    total?: string;
  };
}
 
/* you may need to customize the response */
interface ResponseData<T> {
  total: number;
  records: T[];
  [key: string]: any;
}
 
/* you may need to customize the response */
interface Response<T> {
  code: number;
  error: string;
  res: ResponseData<T>;
  trace: string;
}
 
type Api<T, K> = (params: T) => Promise<Response<K>>;
 
/**
 * Table data request
 * Need to be agreed with the agreement
 * @example const { data, loading, total, pagination, fetchApi } = useTable(api, { defaultParams: { pageNum: 1, pageSize: 10 } });
 */
export const useTable = <T, K = Params>(api: Api<K, T>, options?: Options<K>) => {
  const { manual, defaultParams, paths } = options || {};
  const [data, setData] = useState<T[]>([]);
  const [loading, setLoading] = useState(false);
  const [total, setTotal] = useState(0);
 
  /* you may need to customize the paths */
  const _paths = { data: 'res.records', total: 'res.total', ...paths };
 
  /* you may need to customize the params */
  const _params = useRef<any>({
    pageNum: 1,
    pageSize: 10,
    ...defaultParams,
  });
 
  const pagination = {
    current: _params.current.pageNum,
    pageSize: _params.current.pageSize,
    total,
    showTotal: (total: number) => `共${total}条`,
    showQuickJumper: true,
    showSizeChanger: true,
    onChange: (page: number, pageSize: number) => {
      _params.current.pageNum = page;
      _params.current.pageSize = pageSize;
      fetchApi();
    },
  };
 
  const fetchApi = useCallback((params?: Partial<K>) => {
    _params.current = { ..._params.current, ...params };
    setLoading(true);
  }, []);
 
  useEffect(() => {
    if (!loading) return;
    api(_params.current)
      .then((ress) => {
        /* you may need to customize the response */
        if (ress.code !== 0) throw new Error(ress.error);
        setData(get(ress, _paths.data) || []);
        setTotal(get(ress, _paths.total) || 0);
        setLoading(false);
      })
      .catch((err) => {
        setLoading(false);
        console.error(err);
      });
  }, [loading]);
 
  useEffect(() => {
    if (manual) return;
    fetchApi();
  }, []);
 
  return {
    data,
    loading,
    total,
    pagination,
    fetchApi,
  };
};