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 语言包
This commit is contained in:
31
apps/web/src/hooks/useApiRequest.ts
Normal file
31
apps/web/src/hooks/useApiRequest.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { useCallback } from 'react';
|
||||
import { message } from 'antd';
|
||||
|
||||
function extractErrorMessage(err: unknown): string {
|
||||
if (err && typeof err === 'object' && 'response' in err) {
|
||||
const resp = (err as { response?: { data?: { message?: string } } }).response;
|
||||
return resp?.data?.message || '';
|
||||
}
|
||||
if (err instanceof Error) return err.message;
|
||||
return '';
|
||||
}
|
||||
|
||||
export function useApiRequest() {
|
||||
const execute = useCallback(async <T>(
|
||||
fn: () => Promise<T>,
|
||||
successMsg?: string,
|
||||
errorMsg = '操作失败',
|
||||
): Promise<T | null> => {
|
||||
try {
|
||||
const result = await fn();
|
||||
if (successMsg) message.success(successMsg);
|
||||
return result;
|
||||
} catch (err) {
|
||||
const msg = extractErrorMessage(err);
|
||||
message.error(msg || errorMsg);
|
||||
return null;
|
||||
}
|
||||
}, []);
|
||||
|
||||
return { execute };
|
||||
}
|
||||
Reference in New Issue
Block a user