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 />의 애니메이션이 동작하지 않는 이유는 크게 두 가지다.

  1. 내부 아이템을 직접 선언해서 <Drawer />가 애니메이션을 제대로 적용하지 못하는 경우.
    아이템을 별도 컴포넌트로 분리하여 해결.
  2. 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;