feat(performance): implement comprehensive performance improvements for Worklenz frontend
- Introduced a new document summarizing performance optimizations across the application. - Applied React.memo(), useMemo(), and useCallback() to key components to minimize unnecessary re-renders and optimize rendering performance. - Implemented a route preloading system to enhance navigation speed and user experience. - Added performance monitoring utilities for development to track component render times and function execution. - Enhanced lazy loading and suspense boundaries for better loading states. - Conducted production optimizations, including TypeScript error fixes and memory management improvements. - Memoized style and configuration objects to reduce garbage collection pressure and improve memory usage.
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { ConfigProvider, theme } from 'antd';
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import React, { useEffect, useRef, memo, useMemo, useCallback } from 'react';
|
||||
import { useAppSelector } from '@/hooks/useAppSelector';
|
||||
import { useAppDispatch } from '@/hooks/useAppDispatch';
|
||||
import { initializeTheme } from './themeSlice';
|
||||
@@ -9,12 +9,45 @@ type ChildrenProp = {
|
||||
children: React.ReactNode;
|
||||
};
|
||||
|
||||
const ThemeWrapper = ({ children }: ChildrenProp) => {
|
||||
const ThemeWrapper = memo(({ children }: ChildrenProp) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const themeMode = useAppSelector(state => state.themeReducer.mode);
|
||||
const isInitialized = useAppSelector(state => state.themeReducer.isInitialized);
|
||||
const configRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
// Memoize theme configuration to prevent unnecessary re-renders
|
||||
const themeConfig = useMemo(() => ({
|
||||
algorithm: themeMode === 'dark' ? theme.darkAlgorithm : theme.defaultAlgorithm,
|
||||
components: {
|
||||
Layout: {
|
||||
colorBgLayout: themeMode === 'dark' ? colors.darkGray : colors.white,
|
||||
headerBg: themeMode === 'dark' ? colors.darkGray : colors.white,
|
||||
},
|
||||
Menu: {
|
||||
colorBgContainer: colors.transparent,
|
||||
},
|
||||
Table: {
|
||||
rowHoverBg: themeMode === 'dark' ? '#000' : '#edebf0',
|
||||
},
|
||||
Select: {
|
||||
controlHeight: 32,
|
||||
},
|
||||
},
|
||||
token: {
|
||||
borderRadius: 4,
|
||||
},
|
||||
}), [themeMode]);
|
||||
|
||||
// Memoize the theme class name
|
||||
const themeClassName = useMemo(() => `theme-${themeMode}`, [themeMode]);
|
||||
|
||||
// Memoize the media query change handler
|
||||
const handleMediaQueryChange = useCallback((e: MediaQueryListEvent) => {
|
||||
if (!localStorage.getItem('theme')) {
|
||||
dispatch(initializeTheme());
|
||||
}
|
||||
}, [dispatch]);
|
||||
|
||||
// Initialize theme after mount
|
||||
useEffect(() => {
|
||||
if (!isInitialized) {
|
||||
@@ -26,15 +59,9 @@ const ThemeWrapper = ({ children }: ChildrenProp) => {
|
||||
useEffect(() => {
|
||||
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
||||
|
||||
const handleChange = (e: MediaQueryListEvent) => {
|
||||
if (!localStorage.getItem('theme')) {
|
||||
dispatch(initializeTheme());
|
||||
}
|
||||
};
|
||||
|
||||
mediaQuery.addEventListener('change', handleChange);
|
||||
return () => mediaQuery.removeEventListener('change', handleChange);
|
||||
}, [dispatch]);
|
||||
mediaQuery.addEventListener('change', handleMediaQueryChange);
|
||||
return () => mediaQuery.removeEventListener('change', handleMediaQueryChange);
|
||||
}, [handleMediaQueryChange]);
|
||||
|
||||
// Add CSS transition classes to prevent flash
|
||||
useEffect(() => {
|
||||
@@ -44,34 +71,14 @@ const ThemeWrapper = ({ children }: ChildrenProp) => {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div ref={configRef} className={`theme-${themeMode}`}>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
algorithm: themeMode === 'dark' ? theme.darkAlgorithm : theme.defaultAlgorithm,
|
||||
components: {
|
||||
Layout: {
|
||||
colorBgLayout: themeMode === 'dark' ? colors.darkGray : colors.white,
|
||||
headerBg: themeMode === 'dark' ? colors.darkGray : colors.white,
|
||||
},
|
||||
Menu: {
|
||||
colorBgContainer: colors.transparent,
|
||||
},
|
||||
Table: {
|
||||
rowHoverBg: themeMode === 'dark' ? '#000' : '#edebf0',
|
||||
},
|
||||
Select: {
|
||||
controlHeight: 32,
|
||||
},
|
||||
},
|
||||
token: {
|
||||
borderRadius: 4,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<div ref={configRef} className={themeClassName}>
|
||||
<ConfigProvider theme={themeConfig}>
|
||||
{children}
|
||||
</ConfigProvider>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
});
|
||||
|
||||
ThemeWrapper.displayName = 'ThemeWrapper';
|
||||
|
||||
export default ThemeWrapper;
|
||||
|
||||
Reference in New Issue
Block a user