Files
erp/apps/web/src/hooks/usePaginatedData.ts
iven 9d18b7e079
Some checks failed
CI / rust-check (push) Has been cancelled
CI / rust-test (push) Has been cancelled
CI / frontend-build (push) Has been cancelled
CI / security-audit (push) Has been cancelled
feat(web): Q3 前端体验优化 — ErrorBoundary + 5 hooks + 共享类型 + i18n 基础
- ErrorBoundary 组件:全局错误捕获与优雅降级
- 提取 5 个自定义 hooks:useCountUp, useDarkMode, useDebouncedValue, usePaginatedData, useApiRequest
- 从 11 个 API 文件提取 PaginatedResponse 共享类型到 api/types.ts
- 统一 API 错误处理(api/errors.ts)
- client.ts 迁移到 axios adapter 模式(替代废弃的 CancelToken)
- 添加 react-i18next 国际化基础设施 + zh-CN 语言包
2026-04-17 19:40:58 +08:00

37 lines
1.0 KiB
TypeScript

import { useState, useCallback } from 'react';
import { message } from 'antd';
interface PaginatedState<T> {
data: T[];
total: number;
page: number;
loading: boolean;
}
export function usePaginatedData<T>(
fetchFn: (page: number, pageSize: number, search: string) => Promise<{ data: T[]; total: number }>,
pageSize = 20,
) {
const [state, setState] = useState<PaginatedState<T>>({
data: [],
total: 0,
page: 1,
loading: false,
});
const [searchText, setSearchText] = useState('');
const refresh = useCallback(async (p?: number) => {
const targetPage = p ?? state.page;
setState(s => ({ ...s, loading: true }));
try {
const result = await fetchFn(targetPage, pageSize, searchText);
setState({ data: result.data, total: result.total, page: targetPage, loading: false });
} catch {
message.error('加载数据失败');
setState(s => ({ ...s, loading: false }));
}
}, [fetchFn, pageSize, searchText, state.page]);
return { ...state, searchText, setSearchText, refresh };
}