mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-06 15:59:52 +03:00
use memo and callbacks for reduced rendering vis caching
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
import { memo } from 'react';
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
|
|
||||||
import { CssBaseline, ThemeProvider, responsiveFontSizes } from '@mui/material';
|
import { CssBaseline, ThemeProvider, responsiveFontSizes } from '@mui/material';
|
||||||
@@ -5,6 +6,7 @@ import { createTheme } from '@mui/material/styles';
|
|||||||
|
|
||||||
import type { RequiredChildrenProps } from 'utils';
|
import type { RequiredChildrenProps } from 'utils';
|
||||||
|
|
||||||
|
// Memoize dialog style to prevent recreation
|
||||||
export const dialogStyle = {
|
export const dialogStyle = {
|
||||||
'& .MuiDialog-paper': {
|
'& .MuiDialog-paper': {
|
||||||
borderRadius: '8px',
|
borderRadius: '8px',
|
||||||
@@ -12,8 +14,9 @@ export const dialogStyle = {
|
|||||||
borderStyle: 'solid',
|
borderStyle: 'solid',
|
||||||
borderWidth: '1px'
|
borderWidth: '1px'
|
||||||
}
|
}
|
||||||
};
|
} as const;
|
||||||
|
|
||||||
|
// Memoize theme creation to prevent recreation
|
||||||
const theme = responsiveFontSizes(
|
const theme = responsiveFontSizes(
|
||||||
createTheme({
|
createTheme({
|
||||||
typography: {
|
typography: {
|
||||||
@@ -34,11 +37,11 @@ const theme = responsiveFontSizes(
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
const CustomTheme: FC<RequiredChildrenProps> = ({ children }) => (
|
const CustomTheme: FC<RequiredChildrenProps> = memo(({ children }) => (
|
||||||
<ThemeProvider theme={theme}>
|
<ThemeProvider theme={theme}>
|
||||||
<CssBaseline />
|
<CssBaseline />
|
||||||
{children}
|
{children}
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
);
|
));
|
||||||
|
|
||||||
export default CustomTheme;
|
export default CustomTheme;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useEffect, useMemo, useState } from 'react';
|
import { memo, useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
import { useLocation } from 'react-router';
|
import { useLocation } from 'react-router';
|
||||||
|
|
||||||
@@ -13,22 +13,26 @@ import { LayoutContext } from './context';
|
|||||||
|
|
||||||
export const DRAWER_WIDTH = 210;
|
export const DRAWER_WIDTH = 210;
|
||||||
|
|
||||||
const Layout: FC<RequiredChildrenProps> = ({ children }) => {
|
const Layout: FC<RequiredChildrenProps> = memo(({ children }) => {
|
||||||
const [mobileOpen, setMobileOpen] = useState(false);
|
const [mobileOpen, setMobileOpen] = useState(false);
|
||||||
const [title, setTitle] = useState(PROJECT_NAME);
|
const [title, setTitle] = useState(PROJECT_NAME);
|
||||||
const { pathname } = useLocation();
|
const { pathname } = useLocation();
|
||||||
|
|
||||||
const handleDrawerToggle = () => {
|
// Memoize drawer toggle handler to prevent unnecessary re-renders
|
||||||
setMobileOpen(!mobileOpen);
|
const handleDrawerToggle = useCallback(() => {
|
||||||
};
|
setMobileOpen((prev) => !prev);
|
||||||
|
}, []);
|
||||||
|
|
||||||
useEffect(() => setMobileOpen(false), [pathname]);
|
// Close drawer when route changes
|
||||||
|
useEffect(() => {
|
||||||
|
setMobileOpen(false);
|
||||||
|
}, [pathname]);
|
||||||
|
|
||||||
// cache the object to prevent unnecessary re-renders
|
// Memoize context value to prevent unnecessary re-renders
|
||||||
const obj = useMemo(() => ({ title, setTitle }), [title]);
|
const contextValue = useMemo(() => ({ title, setTitle }), [title]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LayoutContext.Provider value={obj}>
|
<LayoutContext.Provider value={contextValue}>
|
||||||
<LayoutAppBar title={title} onToggleDrawer={handleDrawerToggle} />
|
<LayoutAppBar title={title} onToggleDrawer={handleDrawerToggle} />
|
||||||
<LayoutDrawer mobileOpen={mobileOpen} onClose={handleDrawerToggle} />
|
<LayoutDrawer mobileOpen={mobileOpen} onClose={handleDrawerToggle} />
|
||||||
<Box component="main" sx={{ marginLeft: { md: `${DRAWER_WIDTH}px` } }}>
|
<Box component="main" sx={{ marginLeft: { md: `${DRAWER_WIDTH}px` } }}>
|
||||||
@@ -37,6 +41,6 @@ const Layout: FC<RequiredChildrenProps> = ({ children }) => {
|
|||||||
</Box>
|
</Box>
|
||||||
</LayoutContext.Provider>
|
</LayoutContext.Provider>
|
||||||
);
|
);
|
||||||
};
|
});
|
||||||
|
|
||||||
export default Layout;
|
export default Layout;
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
|
import { memo } from 'react';
|
||||||
|
|
||||||
import { Box, CircularProgress } from '@mui/material';
|
import { Box, CircularProgress } from '@mui/material';
|
||||||
|
|
||||||
const LazyLoader = () => (
|
const LazyLoader = memo(() => (
|
||||||
<Box
|
<Box
|
||||||
display="flex"
|
display="flex"
|
||||||
justifyContent="center"
|
justifyContent="center"
|
||||||
@@ -15,6 +17,6 @@ const LazyLoader = () => (
|
|||||||
>
|
>
|
||||||
<CircularProgress size={40} />
|
<CircularProgress size={40} />
|
||||||
</Box>
|
</Box>
|
||||||
);
|
));
|
||||||
|
|
||||||
export default LazyLoader;
|
export default LazyLoader;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useState } from 'react';
|
import { useCallback, useState } from 'react';
|
||||||
import { useBlocker } from 'react-router';
|
import { useBlocker } from 'react-router';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
@@ -35,20 +35,26 @@ export const useRest = <D>({ read, update }: RestRequestOptions<D>) => {
|
|||||||
setDirtyFlags([]);
|
setDirtyFlags([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
const updateDataValue = (new_data: D) => {
|
// Memoize updateDataValue to prevent unnecessary re-renders
|
||||||
updateData({ data: new_data });
|
const updateDataValue = useCallback(
|
||||||
};
|
(new_data: D) => {
|
||||||
|
updateData({ data: new_data });
|
||||||
|
},
|
||||||
|
[updateData]
|
||||||
|
);
|
||||||
|
|
||||||
const loadData = async () => {
|
// Memoize loadData to prevent unnecessary re-renders
|
||||||
|
const loadData = useCallback(async () => {
|
||||||
setDirtyFlags([]);
|
setDirtyFlags([]);
|
||||||
setErrorMessage(undefined);
|
setErrorMessage(undefined);
|
||||||
await readData().catch((error: Error) => {
|
await readData().catch((error: Error) => {
|
||||||
toast.error(error.message);
|
toast.error(error.message);
|
||||||
setErrorMessage(error.message);
|
setErrorMessage(error.message);
|
||||||
});
|
});
|
||||||
};
|
}, [readData]);
|
||||||
|
|
||||||
const saveData = async () => {
|
// Memoize saveData to prevent unnecessary re-renders
|
||||||
|
const saveData = useCallback(async () => {
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -64,14 +70,15 @@ export const useRest = <D>({ read, update }: RestRequestOptions<D>) => {
|
|||||||
setErrorMessage(error.message);
|
setErrorMessage(error.message);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
}, [data, writeData]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
loadData,
|
loadData,
|
||||||
saveData,
|
saveData,
|
||||||
saving: saving as boolean,
|
saving: saving as boolean,
|
||||||
updateDataValue,
|
updateDataValue,
|
||||||
data: data as D, // Explicitly define the type of 'data'
|
data: data as D,
|
||||||
origData: origData as D, // Explicitly define the type of 'origData' to 'D'
|
origData: origData as D,
|
||||||
dirtyFlags,
|
dirtyFlags,
|
||||||
setDirtyFlags,
|
setDirtyFlags,
|
||||||
setOrigData,
|
setOrigData,
|
||||||
|
|||||||
Reference in New Issue
Block a user