Skip to content

Commit

Permalink
frontend: Use stable references and memoize Sidebar component
Browse files Browse the repository at this point in the history
Signed-off-by: Oleksandr Dubenko <[email protected]>
  • Loading branch information
sniok committed Nov 25, 2024
1 parent bfabcc6 commit 903f101
Showing 1 changed file with 166 additions and 157 deletions.
323 changes: 166 additions & 157 deletions frontend/src/components/Sidebar/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import Drawer from '@mui/material/Drawer';
import Grid from '@mui/material/Grid';
import List from '@mui/material/List';
import useMediaQuery from '@mui/material/useMediaQuery';
import React from 'react';
import React, { memo, useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { useDispatch } from 'react-redux';
import { useHistory } from 'react-router-dom';
Expand Down Expand Up @@ -112,7 +112,7 @@ function SidebarToggleButton() {
);
}

function DefaultLinkArea(props: { sidebarName: string; isOpen: boolean }) {
const DefaultLinkArea = memo((props: { sidebarName: string; isOpen: boolean }) => {
const { sidebarName, isOpen } = props;

if (sidebarName === DefaultSidebars.HOME) {
Expand Down Expand Up @@ -151,7 +151,7 @@ function DefaultLinkArea(props: { sidebarName: string; isOpen: boolean }) {
</Box>
</Box>
);
}
});

export default function Sidebar() {
const { t, i18n } = useTranslation(['glossary', 'translation']);
Expand Down Expand Up @@ -186,6 +186,15 @@ export default function Sidebar() {

const search = namespaces.size !== 0 ? `?namespace=${[...namespaces].join('+')}` : '';

const handleToggleOpen = useCallback(() => {
dispatch(setWhetherSidebarOpen(!sidebar.isSidebarOpen));
}, [sidebar.isSidebarOpen]);

const linkArea = useMemo(
() => <DefaultLinkArea sidebarName={sidebar.selected.sidebar || ''} isOpen={isOpen} />,
[sidebar.selected.sidebar, isOpen]
);

if (sidebar.selected.sidebar === null || !sidebar?.isVisible) {
return null;
}
Expand All @@ -199,10 +208,8 @@ export default function Sidebar() {
isTemporaryDrawer={isTemporaryDrawer}
selectedName={sidebar?.selected.item}
search={search}
onToggleOpen={() => {
dispatch(setWhetherSidebarOpen(!sidebar.isSidebarOpen));
}}
linkArea={<DefaultLinkArea sidebarName={sidebar.selected.sidebar || ''} isOpen={isOpen} />}
onToggleOpen={handleToggleOpen}
linkArea={linkArea}
/>
);
}
Expand All @@ -228,161 +235,163 @@ export interface PureSidebarProps {
linkArea: React.ReactNode;
}

export function PureSidebar({
open,
openUserSelected,
items,
selectedName,
isTemporaryDrawer = false,
isNarrowOnly = false,
onToggleOpen,
search,
linkArea,
}: PureSidebarProps) {
const { t } = useTranslation();
const temporarySideBarOpen = open === true && isTemporaryDrawer && openUserSelected === true;

// The large sidebar does not open in medium view (600-960px).
const largeSideBarOpen =
(open === true && !isNarrowOnly) || (open === true && temporarySideBarOpen);

/**
* For closing the sidebar if temporaryDrawer on mobile.
*/
const toggleDrawer = (event: React.KeyboardEvent | React.MouseEvent) => {
if (
event.type === 'keydown' &&
((event as React.KeyboardEvent).key === 'Tab' ||
(event as React.KeyboardEvent).key === 'Shift')
) {
return;
}
onToggleOpen();
};

const contents = (
<>
<Box
sx={theme => ({
...theme.mixins.toolbar,
})}
/>
<Grid
sx={{
height: '100%',
}}
container
direction="column"
justifyContent="space-between"
wrap="nowrap"
>
<Grid item>
<List
onClick={isTemporaryDrawer ? toggleDrawer : undefined}
onKeyDown={isTemporaryDrawer ? toggleDrawer : undefined}
>
{items.map(item => (
<SidebarItem
key={item.name}
selectedName={selectedName}
fullWidth={largeSideBarOpen}
search={search}
{...item}
/>
))}
</List>
</Grid>
<Grid item>
<Box
textAlign="center"
p={0}
sx={theme => ({
'&, & *, & svg': {
color: theme.palette.sidebarLink.color,
},
'& .MuiButton-root': {
color: theme.palette.sidebarButtonInLinkArea.color,
'&:hover': {
background: theme.palette.sidebarButtonInLinkArea.hover.background,
export const PureSidebar = memo(
({
open,
openUserSelected,
items,
selectedName,
isTemporaryDrawer = false,
isNarrowOnly = false,
onToggleOpen,
search,
linkArea,
}: PureSidebarProps) => {
const { t } = useTranslation();
const temporarySideBarOpen = open === true && isTemporaryDrawer && openUserSelected === true;

// The large sidebar does not open in medium view (600-960px).
const largeSideBarOpen =
(open === true && !isNarrowOnly) || (open === true && temporarySideBarOpen);

/**
* For closing the sidebar if temporaryDrawer on mobile.
*/
const toggleDrawer = (event: React.KeyboardEvent | React.MouseEvent) => {
if (
event.type === 'keydown' &&
((event as React.KeyboardEvent).key === 'Tab' ||
(event as React.KeyboardEvent).key === 'Shift')
) {
return;
}
onToggleOpen();
};

const contents = (
<>
<Box
sx={theme => ({
...theme.mixins.toolbar,
})}
/>
<Grid
sx={{
height: '100%',
}}
container
direction="column"
justifyContent="space-between"
wrap="nowrap"
>
<Grid item>
<List
onClick={isTemporaryDrawer ? toggleDrawer : undefined}
onKeyDown={isTemporaryDrawer ? toggleDrawer : undefined}
>
{items.map(item => (
<SidebarItem
key={item.name}
selectedName={selectedName}
fullWidth={largeSideBarOpen}
search={search}
{...item}
/>
))}
</List>
</Grid>
<Grid item>
<Box
textAlign="center"
p={0}
sx={theme => ({
'&, & *, & svg': {
color: theme.palette.sidebarLink.color,
},
},
'& .MuiButton-containedPrimary': {
background: theme.palette.sidebarButtonInLinkArea.primary.background,
'&:hover': {
background: theme.palette.sidebarButtonInLinkArea.hover.background,
'& .MuiButton-root': {
color: theme.palette.sidebarButtonInLinkArea.color,
'&:hover': {
background: theme.palette.sidebarButtonInLinkArea.hover.background,
},
},
},
})}
>
{linkArea}
</Box>
'& .MuiButton-containedPrimary': {
background: theme.palette.sidebarButtonInLinkArea.primary.background,
'&:hover': {
background: theme.palette.sidebarButtonInLinkArea.hover.background,
},
},
})}
>
{linkArea}
</Box>
</Grid>
</Grid>
</Grid>
</>
);
</>
);

const conditionalProps = isTemporaryDrawer
? {
open: temporarySideBarOpen,
onClose: onToggleOpen,
}
: {};
const conditionalProps = isTemporaryDrawer
? {
open: temporarySideBarOpen,
onClose: onToggleOpen,
}
: {};

return (
<Box component="nav" aria-label={t('translation|Navigation')}>
<Drawer
variant={isTemporaryDrawer ? 'temporary' : 'permanent'}
sx={theme => {
const drawer = {
width: drawerWidth,
flexShrink: 0,
background: theme.palette.sidebarBg,
};

const drawerOpen = {
width: drawerWidth,
transition: theme.transitions.create('width', {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.enteringScreen,
}),
background: theme.palette.sidebarBg,
};

const drawerClose = {
transition: theme.transitions.create('width', {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen,
}),
overflowX: 'hidden',
width: '56px',
[theme.breakpoints.down('xs')]: {
background: 'initial',
},
[theme.breakpoints.down('sm')]: {
width: theme.spacing(0),
},
[theme.breakpoints.up('sm')]: {
width: '72px',
},
background: theme.palette.sidebarBg,
};

if (
(isTemporaryDrawer && temporarySideBarOpen) ||
(!isTemporaryDrawer && largeSideBarOpen)
) {
return { ...drawer, ...drawerOpen, '& .MuiPaper-root': { ...drawerOpen } };
} else {
return { ...drawer, ...drawerClose, '& .MuiPaper-root': { ...drawerClose } };
}
}}
{...conditionalProps}
>
{contents}
</Drawer>
</Box>
);
}
return (
<Box component="nav" aria-label={t('translation|Navigation')}>
<Drawer
variant={isTemporaryDrawer ? 'temporary' : 'permanent'}
sx={theme => {
const drawer = {
width: drawerWidth,
flexShrink: 0,
background: theme.palette.sidebarBg,
};

const drawerOpen = {
width: drawerWidth,
transition: theme.transitions.create('width', {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.enteringScreen,
}),
background: theme.palette.sidebarBg,
};

const drawerClose = {
transition: theme.transitions.create('width', {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen,
}),
overflowX: 'hidden',
width: '56px',
[theme.breakpoints.down('xs')]: {
background: 'initial',
},
[theme.breakpoints.down('sm')]: {
width: theme.spacing(0),
},
[theme.breakpoints.up('sm')]: {
width: '72px',
},
background: theme.palette.sidebarBg,
};

if (
(isTemporaryDrawer && temporarySideBarOpen) ||
(!isTemporaryDrawer && largeSideBarOpen)
) {
return { ...drawer, ...drawerOpen, '& .MuiPaper-root': { ...drawerOpen } };
} else {
return { ...drawer, ...drawerClose, '& .MuiPaper-root': { ...drawerClose } };
}
}}
{...conditionalProps}
>
{contents}
</Drawer>
</Box>
);
}
);

export function useSidebarItem(
sidebarDesc: string | null | { item: string | null; sidebar?: string }
Expand Down

0 comments on commit 903f101

Please sign in to comment.