index.ts 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. import {
  2. createPageContext,
  3. createSearchContext,
  4. useContextSection,
  5. usePage,
  6. useTableSearchState,
  7. } from '@hooks';
  8. import {BaseListResult, GetBaseListType, ListParams, OriginalListParams} from '@models';
  9. import {useQuery} from '@tanstack/react-query';
  10. import {shallowEqual} from '@utils';
  11. import {useLatest} from 'ahooks';
  12. import {useEffect, useRef, useState} from 'react';
  13. type UseQueryListResult<D extends BaseListResult, T extends unknown[] = GetBaseListType<D>[]> = [
  14. {
  15. count: number;
  16. data: T;
  17. isFetching: boolean;
  18. },
  19. {refetch: () => void},
  20. ];
  21. type UseQueryListOptions<
  22. P extends ListParams,
  23. R extends BaseListResult,
  24. T extends Array<unknown> = GetBaseListType<R>[],
  25. > = {
  26. queryFn: (params: P, signal?: AbortSignal) => R;
  27. params: OriginalListParams<P>;
  28. pageContext: ReturnType<typeof createPageContext>;
  29. searchContext: ReturnType<typeof createSearchContext>;
  30. formatResult?: (data: Awaited<R>) => T;
  31. };
  32. export function useQueryTableList<
  33. P extends ListParams,
  34. R extends BaseListResult,
  35. T extends Array<unknown> = GetBaseListType<R>[],
  36. >({
  37. queryFn,
  38. params,
  39. pageContext,
  40. searchContext,
  41. formatResult,
  42. }: UseQueryListOptions<P, R, T>): UseQueryListResult<R, T> {
  43. const [count, setCount] = useState(0);
  44. const [{page, pageSize}, {onCurrentPageChange}] = usePage(pageContext);
  45. const prevData = useRef<T>([] as unknown as T);
  46. const prevParams = useRef(params);
  47. const formatResultFn = useLatest(formatResult);
  48. const {
  49. data = [] as unknown as T,
  50. isFetching,
  51. refetch,
  52. } = useQuery<T>({
  53. queryKey: [queryFn.name, page, pageSize, ...Object.values(params)],
  54. async queryFn({signal}) {
  55. /**
  56. * 当参数发生改变说明请求内容发生变化
  57. * 如果当前页码不为1需要跳转到第1页查询
  58. */
  59. if (page !== 1 && !shallowEqual(prevParams.current, params)) {
  60. prevParams.current = params;
  61. onCurrentPageChange(1);
  62. // 这里可以返回一个空数组
  63. // 记录上一次数据是为了展示 防止闪烁
  64. return prevData.current;
  65. }
  66. /**
  67. * 有可能参数发生变化但是页码为1 第一步不会拦截
  68. * 这里确保参数是最新的参数
  69. */
  70. prevParams.current = params;
  71. const data = await queryFn(
  72. {
  73. ...params,
  74. page: page.toString(),
  75. limit: pageSize.toString(),
  76. } as P,
  77. signal,
  78. );
  79. if (data.msg === '200') {
  80. const {total, list} = data.data;
  81. /**
  82. * 场景:当页面只有一个数据的时候 删除了页码改为前一个 但是数据请求还是当前页码
  83. * 需要判断当前是否无数据并且页码大于1 满足时跳转到前一个页面
  84. */
  85. page > 1 && list.length === 0 && onCurrentPageChange(page - 1);
  86. setCount(total);
  87. }
  88. let res: T;
  89. formatResultFn.current
  90. ? (res = formatResultFn.current(data))
  91. : (res = data.msg === '200' ? (data.data.list as unknown as T) : ([] as unknown as T));
  92. return (prevData.current = res);
  93. },
  94. placeholderData: [] as unknown as T,
  95. keepPreviousData: true,
  96. });
  97. const [, searchChange] = useTableSearchState(searchContext);
  98. // 保持更新搜索表格的查询状态
  99. useEffect(
  100. function () {
  101. searchChange(isFetching);
  102. },
  103. [isFetching, searchChange],
  104. );
  105. const searchDispatch = useContextSection(searchContext, state => state[1]);
  106. useEffect(
  107. function () {
  108. searchDispatch({type: 'CHANGE_SEARCH_FUNCTION', payload: refetch});
  109. },
  110. [refetch, searchDispatch],
  111. );
  112. return [
  113. {
  114. count,
  115. data,
  116. isFetching,
  117. },
  118. {refetch},
  119. ];
  120. }