修复退出登录重定向问题和相关功能优化
- 修复DashboardLayout中的退出登录函数,确保清除所有认证信息 - 恢复_app.tsx中的认证逻辑,确保仪表盘页面需要登录访问 - 完善退出登录流程:清除本地存储 -> 调用登出API -> 重定向到登录页面 - 添加错误边界组件提升用户体验 - 优化React水合错误处理 - 添加JWT令牌验证API - 完善各个仪表盘页面的功能和样式
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
// 开发环境的水合错误调试工具
|
||||
export const hydrationDebug = {
|
||||
// 检查是否在客户端
|
||||
isClient: typeof window !== 'undefined',
|
||||
|
||||
// 检查是否在开发环境
|
||||
isDevelopment: process.env.NODE_ENV === 'development',
|
||||
|
||||
// 记录水合错误
|
||||
logHydrationError: (error: Error, componentName?: string) => {
|
||||
if (hydrationDebug.isDevelopment) {
|
||||
console.group('🔧 Hydration Error Debug');
|
||||
console.error('Component:', componentName || 'Unknown');
|
||||
console.error('Error:', error.message);
|
||||
console.error('Stack:', error.stack);
|
||||
|
||||
// 检查常见的水合错误原因
|
||||
const commonCauses = [
|
||||
'Server and client rendered different content',
|
||||
'useEffect running on server',
|
||||
'Date/time differences',
|
||||
'Random values',
|
||||
'Browser-specific APIs',
|
||||
'localStorage/sessionStorage access',
|
||||
'Window object access'
|
||||
];
|
||||
|
||||
console.warn('Common causes of hydration errors:');
|
||||
commonCauses.forEach((cause, index) => {
|
||||
console.warn(`${index + 1}. ${cause}`);
|
||||
});
|
||||
|
||||
console.groupEnd();
|
||||
}
|
||||
},
|
||||
|
||||
// 安全地访问浏览器 API
|
||||
safeWindowAccess: <T>(callback: () => T, fallback: T): T => {
|
||||
if (hydrationDebug.isClient) {
|
||||
try {
|
||||
return callback();
|
||||
} catch (error) {
|
||||
console.warn('Safe window access failed:', error);
|
||||
return fallback;
|
||||
}
|
||||
}
|
||||
return fallback;
|
||||
},
|
||||
|
||||
// 安全地访问 localStorage
|
||||
safeLocalStorage: {
|
||||
getItem: (key: string): string | null => {
|
||||
return hydrationDebug.safeWindowAccess(
|
||||
() => localStorage.getItem(key),
|
||||
null
|
||||
);
|
||||
},
|
||||
setItem: (key: string, value: string): void => {
|
||||
hydrationDebug.safeWindowAccess(
|
||||
() => localStorage.setItem(key, value),
|
||||
undefined
|
||||
);
|
||||
},
|
||||
removeItem: (key: string): void => {
|
||||
hydrationDebug.safeWindowAccess(
|
||||
() => localStorage.removeItem(key),
|
||||
undefined
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
// 检查环境变量是否在客户端和服务器端一致
|
||||
checkEnvConsistency: () => {
|
||||
if (hydrationDebug.isDevelopment && hydrationDebug.isClient) {
|
||||
const clientEnv = {
|
||||
NEXT_PUBLIC_SUPABASE_URL: process.env.NEXT_PUBLIC_SUPABASE_URL,
|
||||
NEXT_PUBLIC_SUPABASE_ANON_KEY: process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY,
|
||||
NODE_ENV: process.env.NODE_ENV,
|
||||
};
|
||||
|
||||
console.group('🔍 Environment Variables Check');
|
||||
console.log('Client-side environment variables:', clientEnv);
|
||||
|
||||
// 检查是否有未定义的环境变量
|
||||
Object.entries(clientEnv).forEach(([key, value]) => {
|
||||
if (!value) {
|
||||
console.warn(`⚠️ Environment variable ${key} is undefined`);
|
||||
}
|
||||
});
|
||||
|
||||
console.groupEnd();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 在开发环境中自动运行环境变量检查
|
||||
if (hydrationDebug.isDevelopment && hydrationDebug.isClient) {
|
||||
// 延迟执行以避免在初始渲染时执行
|
||||
setTimeout(() => {
|
||||
hydrationDebug.checkEnvConsistency();
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
export default hydrationDebug;
|
||||
@@ -0,0 +1,17 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
/**
|
||||
* 检测组件是否在客户端已挂载的 hook
|
||||
* 用于避免服务器端渲染和客户端渲染不一致导致的水合错误
|
||||
*/
|
||||
export function useClientMount(): boolean {
|
||||
const [isMounted, setIsMounted] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setIsMounted(true);
|
||||
}, []);
|
||||
|
||||
return isMounted;
|
||||
}
|
||||
|
||||
export default useClientMount;
|
||||
@@ -0,0 +1,8 @@
|
||||
import { useEffect, useLayoutEffect } from 'react';
|
||||
|
||||
// 在服务器端使用 useEffect,在客户端使用 useLayoutEffect
|
||||
// 这样可以避免服务器端渲染时的警告
|
||||
export const useIsomorphicLayoutEffect =
|
||||
typeof window !== 'undefined' ? useLayoutEffect : useEffect;
|
||||
|
||||
export default useIsomorphicLayoutEffect;
|
||||
Reference in New Issue
Block a user