Compare commits

...

3 Commits

Author SHA1 Message Date
zdl
d8a4c20565 fix: Login Page Viewed 事件仅在模态框首次打开时触发 1 次
- 验证码倒计时期间不再重复触发
     - 不影响其他事件追踪功能\
2025-11-26 11:15:04 +08:00
zdl
5f959fb44f feat: 添加 认证检查 和 首页渲染 的性能标记 2025-11-26 11:10:50 +08:00
zdl
ee78e00d3b feat: 添加设备检测功能 2025-11-26 11:03:13 +08:00
5 changed files with 77 additions and 3 deletions

View File

@@ -28,6 +28,7 @@ import { useGlobalErrorHandler } from './hooks/useGlobalErrorHandler';
// Redux
import { initializePostHog } from './store/slices/posthogSlice';
import { updateScreenSize } from './store/slices/deviceSlice';
// Utils
import { logger } from './utils/logger';
@@ -63,6 +64,27 @@ function AppContent() {
performanceMonitor.mark('react-ready');
}, []);
// 📱 设备检测:监听窗口尺寸变化
useEffect(() => {
let resizeTimer;
const handleResize = () => {
// 防抖:避免频繁触发
clearTimeout(resizeTimer);
resizeTimer = setTimeout(() => {
dispatch(updateScreenSize());
}, 150);
};
window.addEventListener('resize', handleResize);
window.addEventListener('orientationchange', handleResize);
return () => {
clearTimeout(resizeTimer);
window.removeEventListener('resize', handleResize);
window.removeEventListener('orientationchange', handleResize);
};
}, [dispatch]);
// ✅ 首次访问追踪
useEffect(() => {
const hasVisited = localStorage.getItem('has_visited');

View File

@@ -476,7 +476,8 @@ export default function AuthFormContent() {
return () => {
isMountedRef.current = false;
};
}, [authEvents]);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []); // 仅在挂载时执行一次,避免 countdown 倒计时导致重复触发
return (
<>

View File

@@ -2,8 +2,9 @@
import React, { createContext, useContext, useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { useToast } from '@chakra-ui/react';
import { logger } from '../utils/logger';
import { useNotification } from '../contexts/NotificationContext';
import { logger } from '@utils/logger';
import { performanceMonitor } from '@utils/performanceMonitor';
import { useNotification } from '@contexts/NotificationContext';
import { identifyUser, resetUser, trackEvent } from '@lib/posthog';
import { SPECIAL_EVENTS } from '@lib/constants';
@@ -37,6 +38,9 @@ export const AuthProvider = ({ children }) => {
// 检查Session状态
const checkSession = async () => {
// ⚡ 性能标记:认证检查开始
performanceMonitor.mark('auth-check-start');
// 节流检查
const now = Date.now();
const timeSinceLastCheck = now - lastCheckTimeRef.current;
@@ -47,6 +51,8 @@ export const AuthProvider = ({ children }) => {
minInterval: `${MIN_CHECK_INTERVAL}ms`,
reason: '距离上次请求间隔太短'
});
// ⚡ 性能标记:认证检查结束(节流情况)
performanceMonitor.mark('auth-check-end');
return;
}
@@ -125,6 +131,8 @@ export const AuthProvider = ({ children }) => {
setUser((prev) => prev === null ? prev : null);
setIsAuthenticated((prev) => prev === false ? prev : false);
} finally {
// ⚡ 性能标记:认证检查结束
performanceMonitor.mark('auth-check-end');
// ⚡ 只在 isLoading 为 true 时才设置为 false避免不必要的状态更新
setIsLoading((prev) => prev === false ? prev : false);
}

35
src/hooks/useDevice.js Normal file
View File

@@ -0,0 +1,35 @@
/**
* useDevice Hook
*
* 封装设备类型检测,提供简洁的 API 供组件使用
*
* @example
* const { isMobile, isTablet, isDesktop, deviceType } = useDevice();
*
* if (isMobile) return <MobileView />;
* if (isTablet) return <TabletView />;
* return <DesktopView />;
*/
import { useSelector } from 'react-redux';
import {
selectIsMobile,
selectIsTablet,
selectIsDesktop,
selectDeviceType,
} from '@/store/slices/deviceSlice';
export const useDevice = () => {
const isMobile = useSelector(selectIsMobile);
const isTablet = useSelector(selectIsTablet);
const isDesktop = useSelector(selectIsDesktop);
const deviceType = useSelector(selectDeviceType);
return {
isMobile,
isTablet,
isDesktop,
deviceType,
};
};
export default useDevice;

View File

@@ -9,6 +9,7 @@ import { usePostHogTrack } from '@/hooks/usePostHogRedux';
import { useHomeResponsive } from '@/hooks/useHomeResponsive';
import { ACQUISITION_EVENTS } from '@/lib/constants';
import { CORE_FEATURES } from '@/constants/homeFeatures';
import { performanceMonitor } from '@/utils/performanceMonitor';
import type { Feature } from '@/types/home';
import { HeroBackground } from './components/HeroBackground';
import { HeroHeader } from './components/HeroHeader';
@@ -36,6 +37,11 @@ const HomePage: React.FC = () => {
showDecorations
} = useHomeResponsive();
// ⚡ 性能标记:首页组件挂载 = 渲染开始
useEffect(() => {
performanceMonitor.mark('homepage-render-start');
}, []);
// PostHog 追踪:页面浏览
useEffect(() => {
track(ACQUISITION_EVENTS.LANDING_PAGE_VIEWED, {
@@ -67,6 +73,8 @@ const HomePage: React.FC = () => {
// 背景图片加载完成回调
const handleImageLoad = useCallback(() => {
setImageLoaded(true);
// ⚡ 性能标记:首页渲染完成(背景图片加载完成 = 首屏视觉完整)
performanceMonitor.mark('homepage-render-end');
}, []);
// 特色功能(第一个)