MUI <Drawer /> 애니메이션이 적용되지 않는 이유
MUI의 <Drawer /> 컴포넌트를 사용할 때 애니메이션이 정상적으로 적용되지 않는 경우가 있다. 이번 글에서는 그 원인과 해결 방법을 정리해본다.
1. 애니메이션이 적용되지 않는 이유
MUI <Drawer /> 애니메이션이 동작하지 않는 주된 원인은 드로어 내부 아이템이 별도 컴포넌트로 분리되지 않았기 때문이다.
MUI의 <Drawer />는 내부 아이템을 렌더링할 때 React.cloneElement 등을 활용해 애니메이션을 관리하는데, 이 과정에서 <ListItem> 같은 내부 요소가 별도 컴포넌트로 분리되지 않으면 애니메이션 적용이 제한될 수 있다.
즉, <Drawer /> 내부에서 리스트 아이템을 직접 렌더링하면 애니메이션이 정상적으로 실행되지 않을 가능성이 크다.
2. 해결 방법: <DrawerSection /> 분리
❌ 기존 코드 (애니메이션 미적용)
<Drawer anchor="right" open={mobileOpen} onClose={handleDrawerToggle}>
<Box>
<List>
{navItems.map((item) => (
<ListItem key={item.title}>
<ListItemButton component={Link} href={item.path}>
{item.icon}
<ListItemText primary={item.title} />
</ListItemButton>
</ListItem>
))}
</List>
</Box>
</Drawer>
문제점:
- <Drawer /> 내부에 <ListItem>을 직접 선언했기 때문에 애니메이션 적용이 제한됨.
✅ 해결 코드 (컴포넌트 분리 후 애니메이션 적용)
const DrawerSection = ({ handleDrawerToggle }) => {
return (
<Box onClick={handleDrawerToggle}>
<List>
{navItems.map((item) => (
<DrawerItem key={item.title} item={item} />
))}
</List>
</Box>
);
};
const DrawerItem = ({ item }) => (
<ListItem disablePadding>
<ListItemButton component={Link} href={item.path}>
{item.icon}
<ListItemText primary={item.title} />
</ListItemButton>
</ListItem>
);
해결 방법:
- <ListItem>을 별도 컴포넌트로 분리하여 <Drawer />가 내부 아이템을 제대로 감지하도록 수정.
- 이를 통해 애니메이션이 정상적으로 적용됨.
3. 애니메이션 버그의 원인 (추가 사항)
애니메이션이 적용되지 않는 또 다른 이유로 React Strict Mode에서의 동작 차이가 있을 수 있다.
- variant="temporary"일 때 Modal 내부의 keepMounted={false} 설정이 기본값이면 애니메이션이 적용되지 않을 수 있음.
- 해결 방법: keepMounted={true}로 설정하여 <Drawer />가 언마운트되지 않도록 유지.
<Drawer
anchor="right"
variant="temporary"
open={mobileOpen}
onClose={handleDrawerToggle}
ModalProps={{ keepMounted: true }} // 성능 최적화 + 애니메이션 유지
>
<DrawerSection handleDrawerToggle={handleDrawerToggle} />
</Drawer>
4. 결론
MUI <Drawer />의 애니메이션이 동작하지 않는 이유는 크게 두 가지다.
- 내부 아이템을 직접 선언해서 <Drawer />가 애니메이션을 제대로 적용하지 못하는 경우.
→ 아이템을 별도 컴포넌트로 분리하여 해결. - keepMounted={false}로 설정되어 Strict Mode에서 애니메이션이 끊기는 경우.
→ keepMounted={true}로 변경하여 해결.
위 두 가지를 적용하면 <Drawer /> 애니메이션이 정상적으로 동작하는 것을 확인할 수 있다. 🚀
필자의 코드는 아래와 같다
애니메이션 적용 X
const CommonHeader = () => {
// 드로어 섹션
const DrawerSection = () => {
return (
// ✨ Drawer를 <DrawerSection/>에 추가함
<Drawer
anchor="right"
variant="temporary"
open={mobileOpen}
onClose={handleDrawerToggle}
ModalProps={{
keepMounted: true, // 모바일 성능 향상
}}
sx={{
"& .MuiDrawer-paper": { boxSizing: "border-box", width: drawerWidth },
}}
>
<Box onClick={handleDrawerToggle}>
...드로어 아이템
</Box>
</Drawer>
);
};
////////// Render
return (
<div>
{/* 앱 바 */}
<StyledAppBar position="fixed" elevation={0}>
{/* 드로어 */}
{isMobile && (
<DrawerSection />
)}
</StyledAppBar>
</div>
);
};
export default CommonHeader;
애니메이션 적용 O
const CommonHeader = () => {
// 드로어 섹션
const DrawerSection = () => {
return (
<Box onClick={handleDrawerToggle}>
...드로어 아이템
</Box>
);
};
////////// Render
return (
<div>
{/* 앱 바 */}
<StyledAppBar position="fixed" elevation={0}>
{/* 드로어 */}
{isMobile && (
// ✨ Drawer를 <DrawerSection/>에서 빼냄
<Drawer
anchor="right"
variant="temporary"
open={mobileOpen}
onClose={handleDrawerToggle}
ModalProps={{
keepMounted: true, // 모바일 성능 향상
}}
sx={{
"& .MuiDrawer-paper": { boxSizing: "border-box", width: drawerWidth },
}}
>
<DrawerSection />
</Drawer>
)}
</StyledAppBar>
</div>
);
};
export default CommonHeader;
'라이브러리 > MUI' 카테고리의 다른 글
[MUI] Next15 | notistack 사용방법 | 스낵바 UI 구현 | 토스트 UI 구현 (0) | 2025.03.08 |
---|---|
[MUI] MUI icons 아이콘 컴포넌트 props로 전달받기 | MUI 아이콘 프롭스 타입 정의 방법 (0) | 2025.03.04 |
[MUI] 아코디언 <Accordion/> 기본 그림자(box-shadow) 제거 (0) | 2025.03.03 |
[MUI] Drawer 테두리 둥글게 변경하기 (0) | 2025.02.21 |
[MUI] <Select /> 기본 스타일링 (0) | 2025.02.06 |