UNPKG

@gulibs/react-autoroutes-client

Version:

Client-side utilities for React auto routes

1,412 lines (1,169 loc) 32 kB
# @gulibs/react-autoroutes-client 一个功能强大的 React 路由自动化客户端库,提供完整的路由保护、状态管理、国际化和性能优化解决方案。 ## ✨ 特性 - 🛡️ **路由保护** - 支持认证、权限、角色和自定义守卫 - 🏗️ **中间件系统** - 可插拔的中间件架构 - 🌍 **国际化支持** - 与 @gulibs/vite-plugin-i18n 完美集成 - 📊 **状态管理** - 基于 React Storage 的用户认证状态管理 - ⚡ **性能优化** - 内置缓存、防抖和性能监控 - 🎯 **TypeScript** - 完整的类型定义支持 - 📱 **现代化** - 支持 React 18+ 和现代浏览器 - 🔄 **热更新** - 支持开发时的热模块替换 - 📦 **模块化** - 按需导入,减小包大小 ## 📦 安装 ```bash npm install @gulibs/react-autoroutes-client # 或 pnpm add @gulibs/react-autoroutes-client # 或 yarn add @gulibs/react-autoroutes-client ``` ### 对等依赖 ```bash npm install react react-dom react-router lodash ``` ## 🚀 快速开始 ### 1. 路由保护 ```tsx import { RouteProtectionWrapper, defineAuth, defineGuard } from '@gulibs/react-autoroutes-client'; // 定义认证守卫 const authGuard = defineAuth({ redirectTo: '/login', errorMessage: '请先登录' }); // 定义自定义守卫 const adminGuard = defineGuard({ name: 'admin-only', condition: (context) => context.user?.role === 'admin', redirectTo: '/forbidden', errorMessage: '需要管理员权限' }); function ProtectedPage() { return ( <RouteProtectionWrapper guards={[authGuard, adminGuard]} loadingElement={<div>验证中...</div>} component={<YourPageComponent />} /> ); } ``` ### 2. 用户状态管理 ```tsx import { useUser } from '@gulibs/react-autoroutes-client'; function AuthComponent() { const { user, isAuthenticated, isLoading, login, logout, error } = useUser({ loginApi: async (credentials) => { const response = await fetch('/api/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(credentials) }); return response.json(); }, fetchUser: async (token) => { const response = await fetch('/api/user', { headers: { Authorization: `Bearer ${token}` } }); return response.json(); } }); if (isLoading) return <div>加载中...</div>; if (error) return <div>错误: {error}</div>; return ( <div> {isAuthenticated ? ( <div> <p>欢迎, {user?.name}</p> <button onClick={logout}>退出登录</button> </div> ) : ( <button onClick={() => login({ username: 'demo', password: '123' })}> 登录 </button> )} </div> ); } ``` ### 3. 国际化支持 ```tsx import { I18nProvider, useI18n, createI18nClient } from '@gulibs/react-autoroutes-client'; // 创建国际化客户端 const i18nClient = createI18nClient({ defaultLocale: 'zh', supportedLocales: ['zh', 'en'], resources: { zh: { welcome: '欢迎', hello: '你好, {name}!' }, en: { welcome: 'Welcome', hello: 'Hello, {name}!' } } }); function App() { return ( <I18nProvider client={i18nClient}> <MyComponent /> </I18nProvider> ); } function MyComponent() { const { t, locale, setLocale } = useI18n(); return ( <div> <p>{t('welcome')}</p> <p>{t('hello', { name: '张三' })}</p> <button onClick={() => setLocale(locale === 'zh' ? 'en' : 'zh')}> 切换语言 </button> </div> ); } ``` ### 4. 页面配置和 Hooks ```tsx import { useHandle, usePageConfig, useI18nPageConfig, useVGroveLayoutSettings, useLayoutFeatures, defineHandle } from '@gulibs/react-autoroutes-client'; // 定义页面处理配置 export const handle = defineHandle({ meta: { title: 'page.title', description: '页面描述' }, breadcrumbs: { href: '/current-page', children: '当前页面' }, layoutSettings: { variant: 'modern', sidebar: true, header: true, footer: false, content: { maxWidth: '1400px', padding: '2rem', centered: true, fullWidth: false }, navbar: { sticky: true, transparent: false, height: '72px' }, sidebarConfig: { position: 'left', width: '320px', collapsible: true, defaultCollapsed: false }, theme: { mode: 'dark', primaryColor: '#3b82f6' }, responsive: { hideSidebarOnMobile: true, mobileBreakpoint: '768px' } } }); function MyPage() { // 获取页面配置 const { meta, breadcrumbs, layoutSettings } = usePageConfig(handle); // 获取 VGrove 布局配置(带默认值) const vgroveLayout = useVGroveLayoutSettings(handle); // 获取布局功能状态 const { hasSidebar, hasHeader, hasFooter, isModern, isSidebarCollapsible, shouldHideSidebarOnMobile } = useLayoutFeatures(handle); // 获取国际化页面配置 const i18nConfig = useI18nPageConfig(handle); return ( <div> <h1>{meta?.title}</h1> {hasSidebar && <div>显示侧边栏</div>} {hasHeader && <div>显示头部</div>} {/* 页面内容 */} </div> ); } ``` ## 🎯 高级用法 ### 中间件系统 ```tsx import { defineMiddleware } from '@gulibs/react-autoroutes-client'; const loggingMiddleware = defineMiddleware({ name: 'logging', priority: 10, handler: async (context, next) => { console.log(`访问页面: ${context.path}`); const start = Date.now(); await next(); const duration = Date.now() - start; console.log(`页面处理耗时: ${duration}ms`); } }); // 全局性能监控中间件 const performanceMiddleware = defineMiddleware({ name: 'performance', priority: 1, handler: async (context, next) => { if (window.performance) { const mark = `route-${context.path}-start`; performance.mark(mark); } await next(); if (window.performance) { const endMark = `route-${context.path}-end`; performance.mark(endMark); performance.measure(`route-${context.path}`, `route-${context.path}-start`, endMark); } } }); <RouteProtectionWrapper middlewares={[performanceMiddleware, loggingMiddleware]} component={<YourComponent />} /> ``` ### 国际化资源加载器 ```tsx import { createI18nLoader, ViteI18nLoader, createI18nClient } from '@gulibs/react-autoroutes-client'; // 1. 基础资源加载器 const loader = createI18nLoader({ basePath: '/api/locales', extensions: ['.json'], cache: true, debug: true }); // 2. 自定义获取函数 const customLoader = createI18nLoader({ fetchResources: async (locale, path) => { const response = await fetch(`/api/i18n/${locale}`); if (!response.ok) { throw new Error(`Failed to load locale: ${response.statusText}`); } return response.json(); }, onLoad: (locale, data) => { console.log(`✅ Loaded ${locale}:`, Object.keys(data)); }, onError: (locale, error) => { console.error(`❌ Failed to load ${locale}:`, error); } }); // 3. 高级加载器实例 const advancedLoader = new ViteI18nLoader({ basePath: '/locales', cache: true, cacheTime: 30 * 60 * 1000, // 30分钟 debug: process.env.NODE_ENV === 'development' }); // 4. 与国际化客户端集成 const i18nClient = createI18nClient({ defaultLocale: 'zh', supportedLocales: ['zh', 'en'], basePath: '/api/locales', cache: true, detectBrowserLanguage: true, persistence: { enabled: true, key: 'user_locale', storage: 'localStorage' } }); // 5. 手动预加载资源 await loader.preloadResources(['zh', 'en']); // 6. 检查加载器状态 console.log('Available keys:', loader.getAvailableKeys?.()); console.log('Has key "welcome":', loader.hasKey?.('welcome')); console.log('Using virtual module:', advancedLoader.isUsingVirtualModule?.()); ``` ### 复杂路由守卫 ```tsx // 角色守卫 const roleGuard = defineAuth({ roles: ['admin', 'moderator'], redirectTo: '/login', errorMessage: '需要以下角色之一: admin, moderator' }); // 权限守卫 const permissionGuard = defineGuard({ name: 'permission-user:read,user:write', condition: (context) => { return context.user?.permissions?.includes('user:read') && context.user?.permissions?.includes('user:write'); }, redirectTo: '/forbidden', errorMessage: '需要以下权限: user:read, user:write' }); // 自定义复合守卫 const complexGuard = defineGuard({ name: 'complex-auth', condition: async (context) => { // 检查用户是否已认证 if (!context.user) return false; // 检查时间限制 const now = new Date(); const workingHours = now.getHours() >= 9 && now.getHours() <= 18; // 检查用户类型和时间 return context.user.type === 'employee' ? workingHours : true; }, redirectTo: '/access-denied', errorMessage: '当前时间段无法访问' }); // 环境守卫 const environmentGuard = defineGuard({ name: 'environment', condition: () => { return process.env.NODE_ENV === 'development' || localStorage.getItem('feature_flag_enabled') === 'true'; }, redirectTo: '/not-available' }); ``` ### 性能优化工具 ```tsx import { PerformanceCache, BatchProcessor, PerformanceTracker, MemoryOptimizer } from '@gulibs/react-autoroutes-client'; // 创建缓存实例 const cache = new PerformanceCache<string, any>(100); // 批处理器 const processor = new BatchProcessor(5, 100); // 性能追踪 const tracker = new PerformanceTracker(); // 内存优化器 const memoryOptimizer = MemoryOptimizer.getInstance(); function useOptimizedData() { useEffect(() => { // 启动性能追踪 tracker.startTimer('data-loading'); // 批处理数据加载 const loadData = async () => { const items = ['user', 'settings', 'permissions']; const results = await processor.processBatch( items, async (item) => { const cached = cache.get(item); if (cached) return cached; const data = await fetchData(item); cache.set(item, data); return data; } ); return results; }; loadData().finally(() => { const duration = tracker.endTimer('data-loading'); console.log(`数据加载耗时: ${duration}ms`); }); // 注册清理任务 memoryOptimizer.addCleanupTask(() => { cache.clear(); }); return () => { memoryOptimizer.runCleanup(); }; }, []); } ``` ### 工具函数和实用程序 ```tsx import { normalizePath, parseQuery, buildQuery, debounce, throttle, deepMerge, safeParseInt, isEmpty, measureTime } from '@gulibs/react-autoroutes-client'; // 路径处理 const normalizedPath = normalizePath('//path//to//page//'); // => '/path/to/page' // 查询参数处理 const params = parseQuery('?name=john&age=25&active=true'); // => { name: 'john', age: '25', active: 'true' } const query = buildQuery({ name: 'jane', age: 30 }); // => 'name=jane&age=30' // 防抖和节流 const debouncedSearch = debounce((query: string) => { searchAPI(query); }, 500); const throttledScroll = throttle(() => { updateScrollPosition(); }, 100); // 性能测量 const timedFunction = measureTime(expensiveFunction, 'expensive-operation'); // 数据处理 const config = deepMerge(defaultConfig, userConfig); const count = safeParseInt(userInput, 0); const hasData = !isEmpty(responseData); ``` ## 📖 API 参考 ### 路由保护 #### `RouteProtectionWrapper` 路由保护包装器组件。 **Props:** ```typescript interface RouteProtectionWrapperProps { guards?: (AuthOptions | GuardOptions | Function)[]; middlewares?: (MiddlewareOptions | Function)[]; loadingElement?: React.ReactNode; component: React.ReactNode; children?: React.ReactNode; } ``` #### `defineAuth(options: AuthOptions)` 定义认证守卫。 ```typescript interface AuthOptions { name?: string; redirectTo?: string; errorMessage?: string; check?: (context: AuthContext) => boolean | Promise<boolean>; roles?: string[]; permissions?: string[]; } ``` #### `defineGuard(options: GuardOptions)` 定义自定义守卫。 ```typescript interface GuardOptions { name?: string; type?: 'auth' | 'role' | 'permission' | 'custom'; redirectTo?: string; errorMessage?: string; condition: (context: GuardContext) => boolean | Promise<boolean>; } ``` #### `defineMiddleware(options: MiddlewareOptions)` 定义中间件。 ```typescript interface MiddlewareOptions { name?: string; priority?: number; devOnly?: boolean; handler: (context: MiddlewareContext, next: () => Promise<void> | void) => Promise<void> | void; } ``` ### 状态管理 #### `useUser<TUser, TCredentials>(options: UseUserOptions)` 用户状态管理 Hook。 **返回值:** ```typescript interface AuthState<TUser> & AuthActions<TUser, TCredentials> { user: TUser | null; token: string | null; refreshToken: string | null; isAuthenticated: boolean; isLoading: boolean; error: string | null; login: (credentials: TCredentials) => Promise<void>; logout: () => void; refreshUser: () => Promise<void>; refreshTokenAction: () => Promise<void>; updateUser: (userData: Partial<TUser>) => void; setToken: (token: string) => void; setRefreshToken: (refreshToken: string) => void; clearError: () => void; } ``` #### `useStorage<T>(key: string, defaultValue: T, options?)` 通用存储 Hook。 ```typescript function useStorage<T>( key: string, defaultValue: T, options?: { storage?: 'local' | 'session' } ): [T, (value: T) => void, () => void] ``` ### 国际化 #### `I18nProvider` 国际化提供者组件。 ```typescript interface I18nProviderProps { children: ReactNode; client?: I18nClient | I18nClientConfig; defaultLocale?: string; locales?: string[]; loadResources?: (locale: string) => Promise<Record<string, any>>; resources?: Record<string, Record<string, any>>; } ``` #### `useI18n()` 国际化 Hook。 ```typescript interface I18nContextType { locale: string; setLocale: (locale: string) => Promise<void>; t: (key: string, params?: Record<string, any>) => string; isReady: boolean; availableLocales: string[]; availableKeys: string[]; hasKey: (key: string) => boolean; getNamespaceResources: (namespace: string) => Record<string, any> | undefined; isUsingVirtualModule: boolean; } ``` #### `createI18nClient(config: I18nClientConfig)` 创建国际化客户端。 ```typescript interface I18nClientConfig extends I18nLoaderConfig { defaultLocale: string; supportedLocales?: string[]; resources?: Record<string, Record<string, any>>; fallbackToDefault?: boolean; detectBrowserLanguage?: boolean; persistence?: { enabled?: boolean; key?: string; storage?: 'localStorage' | 'sessionStorage'; }; interpolation?: { prefix?: string; suffix?: string; escape?: (value: any) => string; }; } ``` #### `createI18nLoader(config: I18nLoaderConfig)` 创建资源加载器。 ```typescript interface I18nLoaderConfig { basePath?: string; extensions?: string[]; localePattern?: 'directory' | 'filename'; defaultLocale?: string; cacheTime?: number; cache?: boolean; debug?: boolean; onLoad?: (locale: string, data: Record<string, any>) => void; onError?: (locale: string, error: Error) => void; fetchResources?: (locale: string, path: string) => Promise<Record<string, any>>; } ``` ### 页面配置 #### `usePageConfig<Keys>(handle?, options?)` 获取页面配置。 #### `useI18nPageConfig<Keys>(handle?)` 获取国际化页面配置。 #### `useHandle<Keys>()` 获取当前页面的 handle。 #### `useBreadcrumbs<Keys>(handle?, options?)` 获取面包屑配置。 #### `useDocumentTitle<Keys>(handle?, suffix?, options?)` 设置文档标题。 #### `useVGroveLayoutSettings<Keys>(handle?, defaults?)` 获取 VGrove 布局配置,带默认值处理。 ```typescript function useVGroveLayoutSettings<Keys extends string = string>( handle?: PageHandle<Keys>, defaults?: Partial<LayoutSettings> ): LayoutSettings ``` #### `useLayoutFeatures<Keys>(handle?)` 检查布局功能是否启用。 ```typescript interface LayoutFeatures { hasSidebar: boolean; hasHeader: boolean; hasFooter: boolean; isCompact: boolean; isModern: boolean; isMinimal: boolean; isSidebarCollapsible: boolean; isNavbarSticky: boolean; isFooterSticky: boolean; shouldHideSidebarOnMobile: boolean; } ``` #### `useLayoutConfig<Keys>(section, handle?)` 获取布局配置的特定部分。 ```typescript function useLayoutConfig<Keys extends string = string>( section: keyof LayoutSettings, handle?: PageHandle<Keys> ): any ``` #### `LayoutSettings` 接口 VGrove 布局配置接口,支持完整的布局定制。 ```typescript interface LayoutSettings { /** 布局变体 */ variant?: 'default' | 'compact' | 'modern' | 'minimal' | string; /** 是否显示侧边栏 */ sidebar?: boolean; /** 是否显示导航栏/头部 */ header?: boolean; /** 是否显示页脚 */ footer?: boolean; /** 内容区域配置 */ content?: { /** 内容最大宽度 */ maxWidth?: string; /** 内容内边距 */ padding?: string; /** 是否居中对齐 */ centered?: boolean; /** 是否全宽显示 */ fullWidth?: boolean; }; /** 导航栏配置 */ navbar?: { /** 是否固定在顶部 */ sticky?: boolean; /** 背景透明度 */ transparent?: boolean; /** 高度 */ height?: string; }; /** 侧边栏配置 */ sidebarConfig?: { /** 侧边栏位置 */ position?: 'left' | 'right'; /** 侧边栏宽度 */ width?: string; /** 是否可折叠 */ collapsible?: boolean; /** 默认是否折叠 */ defaultCollapsed?: boolean; }; /** 页脚配置 */ footerConfig?: { /** 是否固定在底部 */ sticky?: boolean; /** 高度 */ height?: string; }; /** 主题相关配置 */ theme?: { /** 主题模式 */ mode?: 'light' | 'dark' | 'auto'; /** 主色调 */ primaryColor?: string; }; /** 响应式配置 */ responsive?: { /** 移动端是否隐藏侧边栏 */ hideSidebarOnMobile?: boolean; /** 移动端断点 */ mobileBreakpoint?: string; }; } ``` ### 性能优化 #### `PerformanceCache<K, V>` 高性能 LRU 缓存。 ```typescript class PerformanceCache<K, V> { constructor(maxSize: number = 100); get(key: K): V | undefined; set(key: K, value: V): void; has(key: K): boolean; delete(key: K): boolean; clear(): void; size(): number; } ``` #### `BatchProcessor` 批处理器。 ```typescript class BatchProcessor { constructor(batchSize: number = 10, delay: number = 50); async processBatch<T, R>( items: T[], processor: (item: T) => Promise<R> ): Promise<R[]>; } ``` #### `PerformanceTracker` 性能追踪器。 ```typescript class PerformanceTracker { startTimer(name: string): void; endTimer(name: string): number; increment(name: string): void; getCounter(name: string): number; reset(): void; getStats(): Record<string, any>; } ``` ## 🏆 最佳实践 ### 1. VGrove 布局配置最佳实践 ```tsx // layout/LayoutProvider.tsx import { useVGroveLayoutSettings, useLayoutFeatures } from '@gulibs/react-autoroutes-client'; import { VGroveLayout } from '@gulibs/vgrove-ui'; export function LayoutProvider({ children, handle }) { // 获取完整的布局配置 const layoutConfig = useVGroveLayoutSettings(handle, { // 全局默认配置 variant: 'modern', content: { maxWidth: '1400px', padding: '1.5rem' }, theme: { mode: 'light' } }); // 获取布局功能状态 const features = useLayoutFeatures(handle); return ( <VGroveLayout config={layoutConfig} features={features} > {children} </VGroveLayout> ); } // pages/dashboard/handle.ts import { defineHandle } from '@gulibs/react-autoroutes-client'; export const handle = defineHandle({ meta: { title: 'dashboard.title', description: 'dashboard.description' }, layoutSettings: { variant: 'modern', sidebar: true, header: true, footer: false, content: { maxWidth: '100%', fullWidth: true, padding: '0' }, sidebarConfig: { width: '280px', collapsible: true, defaultCollapsed: false }, navbar: { sticky: true, height: '64px' }, responsive: { hideSidebarOnMobile: true } } }); // pages/dashboard/page.tsx import { useVGroveLayoutSettings } from '@gulibs/react-autoroutes-client'; import { handle } from './handle'; export default function DashboardPage() { const layoutConfig = useVGroveLayoutSettings(handle); return ( <div className="dashboard"> <h1>仪表板</h1> {/* 根据布局配置显示内容 */} </div> ); } // pages/settings/handle.ts export const handle = defineHandle({ meta: { title: 'settings.title' }, layoutSettings: { variant: 'compact', sidebar: false, header: true, footer: true, content: { maxWidth: '800px', centered: true, padding: '2rem' } } }); ``` ### 2. 路由守卫组织 ```tsx // guards/index.ts export const authGuard = defineAuth({ redirectTo: '/login', errorMessage: '请先登录' }); export const adminGuard = defineAuth({ roles: ['admin'], redirectTo: '/forbidden', errorMessage: '需要管理员权限' }); export const premiumGuard = defineGuard({ name: 'premium', condition: (context) => context.user?.isPremium, redirectTo: '/upgrade', errorMessage: '需要升级到高级版' }); // guards/factory.ts export function createRoleGuard(roles: string[], redirectTo = '/forbidden') { return defineAuth({ roles, redirectTo, errorMessage: `需要以下角色之一: ${roles.join(', ')}` }); } export function createPermissionGuard(permissions: string[], redirectTo = '/forbidden') { return defineGuard({ name: `permission-${permissions.join('-')}`, condition: (context) => { return permissions.every(permission => context.user?.permissions?.includes(permission) ); }, redirectTo, errorMessage: `需要以下权限: ${permissions.join(', ')}` }); } ``` ### 3. 国际化最佳实践 ```tsx // i18n/setup.ts import { createI18nClient } from '@gulibs/react-autoroutes-client'; export const i18nClient = createI18nClient({ defaultLocale: 'zh', supportedLocales: ['zh', 'en'], fallbackToDefault: true, detectBrowserLanguage: true, persistence: { enabled: true, key: 'app_locale', storage: 'localStorage' }, interpolation: { prefix: '{', suffix: '}', escape: (value) => String(value).replace(/[<>]/g, '') }, debug: process.env.NODE_ENV === 'development', // 开发环境短缓存,生产环境长缓存 cacheTime: process.env.NODE_ENV === 'production' ? 24 * 60 * 60 * 1000 : 5 * 60 * 1000, onError: (locale, error) => { // 发送错误到监控系统 console.error(`Failed to load locale ${locale}:`, error); // 可以集成 Sentry 等错误监控 }, onLoad: (locale, data) => { console.log(`✅ Loaded ${locale} with ${Object.keys(data).length} keys`); } }); // hooks/useI18nHelpers.ts export function useI18nHelpers() { const { hasKey, validateKey } = useI18nKeyValidator(); const plural = usePlural(); const translateLocalized = useTranslateLocalized(); return { hasKey, validateKey, plural, translateLocalized, // 安全翻译函数,键不存在时返回键名 safeT: (key: string, params?: Record<string, any>) => { const { t } = useI18n(); return hasKey(key) ? t(key, params) : key; } }; } ``` ### 3. 性能优化策略 ```tsx // utils/performance.ts import { PerformanceCache, BatchProcessor, MemoryOptimizer } from '@gulibs/react-autoroutes-client'; // 全局缓存实例 export const globalCache = new PerformanceCache<string, any>(200); export const batchProcessor = new BatchProcessor(10, 100); export const memoryOptimizer = MemoryOptimizer.getInstance(); // 启动内存优化 memoryOptimizer.startPeriodicCleanup(5 * 60 * 1000); // 5分钟清理一次 // hooks/useOptimizedApi.ts export function useOptimizedApi() { const cache = useMemo(() => new PerformanceCache<string, any>(50), []); const fetchWithCache = useCallback(async (url: string) => { const cached = cache.get(url); if (cached) return cached; const response = await fetch(url); const data = await response.json(); cache.set(url, data); return data; }, [cache]); const batchFetch = useCallback(async (urls: string[]) => { return batchProcessor.processBatch(urls, fetchWithCache); }, [fetchWithCache]); useEffect(() => { // 注册清理任务 memoryOptimizer.addCleanupTask(() => { cache.clear(); }); }, [cache]); return { fetchWithCache, batchFetch }; } ``` ### 4. 错误处理 ```tsx // utils/errorBoundary.tsx import { defineGuard } from '@gulibs/react-autoroutes-client'; export const errorHandlingGuard = defineGuard({ name: 'error-handling', condition: async (context) => { try { // 检查用户权限 if (!context.user) return false; // 检查网络状态 if (!navigator.onLine) { throw new Error('网络连接已断开'); } return true; } catch (error) { // 发送错误到监控系统 console.error('Guard error:', error); return false; } }, redirectTo: '/error' }); // components/ErrorBoundary.tsx class ErrorBoundary extends React.Component< { children: React.ReactNode }, { hasError: boolean; error?: Error } > { constructor(props: any) { super(props); this.state = { hasError: false }; } static getDerivedStateFromError(error: Error) { return { hasError: true, error }; } componentDidCatch(error: Error, errorInfo: React.ErrorInfo) { console.error('ErrorBoundary caught an error:', error, errorInfo); // 发送错误到监控系统 } render() { if (this.state.hasError) { return ( <div className="error-fallback"> <h2>出现了一些问题</h2> <details style={{ whiteSpace: 'pre-wrap' }}> {this.state.error?.message} </details> </div> ); } return this.props.children; } } ``` ## 🚨 故障排除 ### 常见问题 #### 1. 虚拟模块加载失败 **症状:** 错误信息 `Failed to resolve import "~i18n-locales-loader"` **解决方案:** ```bash # 检查插件配置 # vite.config.ts 中确保有: import i18nPlugin from '@gulibs/vite-plugin-i18n'; export default defineConfig({ plugins: [ i18nPlugin({ basePath: 'src/locales', keysOutput: 'src/i18n-keys.ts' }) ] }); # 重启开发服务器 npm run dev ``` #### 2. 认证状态不同步 **症状:** 页面刷新后用户状态丢失 **解决方案:** ```tsx // 确保正确配置 useUser const { user, isAuthenticated } = useUser({ storagePrefix: 'myapp', // 使用唯一前缀 useSessionStorage: false, // 使用 localStorage 持久化 autoRefreshInterval: 15 * 60 * 1000, // 15分钟自动刷新 }); // 检查 localStorage console.log('Stored token:', localStorage.getItem('myapp_token')); console.log('Stored user:', localStorage.getItem('myapp_user')); ``` #### 3. 路由保护不生效 **症状:** 守卫没有阻止未授权访问 **解决方案:** ```tsx // 检查 RouteProtectionWrapper 的使用 <RouteProtectionWrapper guards={[authGuard]} // 确保守卫已正确定义 loadingElement={<div>验证中...</div>} // 提供加载状态 component={<ProtectedComponent />} > {/* 不要在这里放置组件 */} </RouteProtectionWrapper> // 确保守卫返回布尔值 const authGuard = defineAuth({ check: (context) => { console.log('Auth check:', context.user); // 调试日志 return !!context.user; // 明确返回布尔值 } }); ``` #### 4. 资源加载失败 **症状:** 国际化资源无法加载 **解决方案:** ```tsx // 启用调试模式 const loader = createI18nLoader({ debug: true, // 查看详细加载日志 onError: (locale, error) => { console.error(`Loading ${locale} failed:`, error); // 检查网络请求是否成功 } }); // 检查资源路径 // 确保服务器上存在对应文件 fetch('/locales/zh.json') .then(res => res.json()) .then(data => console.log('Resource loaded:', data)) .catch(err => console.error('Resource load failed:', err)); // 检查 CORS 设置(如果是跨域请求) ``` #### 5. 性能问题 **症状:** 页面加载缓慢 **解决方案:** ```tsx // 启用缓存 const cache = new PerformanceCache<string, any>(100); // 预加载关键资源 useEffect(() => { // 预加载用户常用语言 loader.preloadResources(['zh', 'en']); // 预加载关键数据 batchProcessor.processBatch( ['user', 'settings', 'permissions'], async (item) => await fetchData(item) ); }, []); // 使用 React.memo 优化组件 const OptimizedComponent = React.memo(function MyComponent(props) { // 组件实现 }); // 使用 useMemo 缓存计算结果 const expensiveValue = useMemo(() => { return heavyComputation(data); }, [data]); ``` #### 6. TypeScript 类型错误 **症状:** TypeScript 编译错误 **解决方案:** ```typescript // 确保导入正确的类型 import type { AuthOptions, GuardOptions, I18nClientConfig } from '@gulibs/react-autoroutes-client'; // 为用户数据定义接口 interface User { id: string; name: string; role: string; permissions: string[]; } // 使用泛型 const { user } = useUser<User, LoginCredentials>({ // 配置... }); // 确保 tsconfig.json 包含正确设置 { "compilerOptions": { "moduleResolution": "node", "esModuleInterop": true, "allowSyntheticDefaultImports": true } } ``` ### 调试工具 ```tsx // 开发工具组件 function DevTools() { const { locale, availableKeys, isUsingVirtualModule } = useI18n(); const { user, isAuthenticated } = useUser(); if (process.env.NODE_ENV !== 'development') return null; return ( <div style={{ position: 'fixed', top: 0, right: 0, background: '#f0f0f0', padding: '10px' }}> <h4>调试信息</h4> <p>当前语言: {locale}</p> <p>翻译键数量: {availableKeys.length}</p> <p>使用虚拟模块: {isUsingVirtualModule ? '是' : '否'}</p> <p>用户认证: {isAuthenticated ? '已登录' : '未登录'}</p> <p>用户信息: {JSON.stringify(user, null, 2)}</p> </div> ); } ``` ## 📈 性能基准 | 功能 | 冷启动 | 热启动 | 内存占用 | |------|--------|--------|----------| | 基础路由保护 | ~10ms | ~2ms | ~50KB | | 国际化加载 | ~20ms | ~5ms | ~100KB | | 完整功能 | ~50ms | ~10ms | ~200KB | ## 🤝 与其他库集成 ### 与状态管理库集成 ```tsx // 与 Redux Toolkit 集成 import { createSlice } from '@reduxjs/toolkit'; import { useUser } from '@gulibs/react-autoroutes-client'; const authSlice = createSlice({ name: 'auth', initialState: { user: null, token: null }, reducers: { setAuth: (state, action) => { state.user = action.payload.user; state.token = action.payload.token; } } }); function useAuthSync() { const dispatch = useDispatch(); const { user, token } = useUser(); useEffect(() => { if (user && token) { dispatch(authSlice.actions.setAuth({ user, token })); } }, [user, token, dispatch]); } ```