라이브러리를 사용하지 않고 슬라이드 애니메이션이 들어간 사이드바를 만들어봤다.
// Router.tsx
...
const Router = () => {
const [isMenuOpen, setIsMenuOpen] = useState<boolean>(false);
const toggleMenu = () => {
setIsMenuOpen(!isMenuOpen);
};
return (
<BrowserRouter>
<HeaderMolecule toggleMenu={toggleMenu} />
{isMenuOpen && (
<SidebarOrganism toggleMenu={toggleMenu} isMenuOpen={isMenuOpen} />
)}
{url == '/' ? null : <PrevMolecule />}
<Routes>
<Route path="/" element={<Main />} />
...
</Routes>
</BrowserRouter>
);
};
export default Router;
// SidebarOrganism.tsx
...
interface SidebarProps {
toggleMenu?: () => void;
isMenuOpen: boolean;
}
const SidebarOrganism = ({ toggleMenu, isMenuOpen }: SidebarProps) => {
...
return (
<SidebarWrapper onClick={toggleMenu}>
<Sidebar isMenuOpen={isMenuOpen} onClick={handleSidebarClick}>
<Close toggleMenu={toggleMenu} />
<SidebarUserStateMolecule />
<BreakLine width={'280'} height={'5'} mb={'30'} />
{menuItems.map((item, index) => (
<SidebarMenuMolecule
key={index}
txt={item.txt}
onClick={() => {
navigate(item.route);
if (toggleMenu) toggleMenu();
}}
/>
))}
<Text
width={'280'}
height={'16'}
fonts={'16'}
fontw={'700'}
bottom={'20'}
cursor={'pointer'}
color={COLORS.gray}
position={'absolute'}
txt={'로그아웃'}
/>
</Sidebar>
</SidebarWrapper>
);
};
export default SidebarOrganism;
열릴 때의 애니메이션은 정상 작동하지만 반대의 닫히는 애니메이션은 동작하지 않음.
당장은 이유를 잘 모르겠어서
1. 연관된 4개의 컴포넌트를 번갈아 고치기 싫어 관련 코드 구조를 변경하고
2. 추가로 animation의 상태를 만들어 따로 관리를 해보기로 했다.
// Router.tsx
...
const Router = () => {
const [isSidebarOpen, setisSidebarOpen] = useState<boolean>(false); // 상태명 변경함
return (
<BrowserRouter>
<HeaderMolecule setisSidebarOpen={setisSidebarOpen} />
{isSidebarOpen && <SidebarOrganism setisSidebarOpen={setisSidebarOpen} />}
{url == '/' ? null : <PrevMolecule />}
<Routes>
<Route path="/" element={<Main />} />
...
</Routes>
</BrowserRouter>
);
};
export default Router;
// SidebarOrganism.tsx
...
interface AnimationProps {
animation: typeof slideIn | typeof slideOut;
}
const SidebarOrganism = () => {
const navigate = useNavigate();
const dispatch = useDispatch();
// close 시 애니메이션 동작하지 않아 상태 추가
const [sidebarOpen, setSidebarOpen] = useState<boolean>(false);
// SidebarWrapper or Close 클릭 시 side bar 닫기
const handletoggleSidebar = () => {
setSidebarOpen(!sidebarOpen);
// side bar를 닫을 때 setTimeOut 시간 후 sidebarWrapper를 없애주기
if (!sidebarOpen) {
setTimeout(() => {
dispatch(toggleSidebar());
}, 200); // 애니메이션의 지속 시간과 같게 설정하면 깜빡임 발생함
}
};
// 사이드바 내 요소가 아닌 부분 클릭 시 상태 유지 (현재 사이드바를 벗어나지 않도록 함)
const handleSidebarClick = (e: React.MouseEvent) => {
e.stopPropagation();
};
// 사이드바 메뉴
const menuItems = [
{ txt: '검색', route: '/search' },
{ txt: '지도', route: '/map' },
{ txt: '전체 리스트', route: '/list' },
{ txt: '마이페이지', route: '/my' },
];
return (
<SidebarWrapper onClick={handletoggleSidebar}>
<Sidebar
onClick={handleSidebarClick}
animation={sidebarOpen ? slideOut : slideIn}
>
<Close handletoggleSidebar={handletoggleSidebar} />
<SidebarUserStateMolecule />
<BreakLine width={'280'} height={'5'} mb={'30'} />
{menuItems.map((item, index) => (
<SidebarMenuMolecule
key={index}
txt={item.txt}
onClick={() => {
navigate(item.route);
// 라우터 이동 시 사이드바 닫히게
if (handletoggleSidebar) handletoggleSidebar();
}}
/>
))}
<Text
width={'280'}
height={'16'}
fonts={'16'}
fontw={'700'}
bottom={'20'}
cursor={'pointer'}
color={COLORS.gray}
position={'absolute'}
txt={'로그아웃'}
/>
</Sidebar>
</SidebarWrapper>
);
};
export default SidebarOrganism;
먼저,
1. 기존 라우터에서 관리하던 사이드바 여닫힘 전환을 헤더로 옮겼다.
2. 그리고 라우터에서는 사이드바 상태만 관리하고 set 함수를 헤더와 사이드바 컴포넌트에 데이터를 넘겨줬다.
3. props로 받은 set 함수들은 각 컴포넌트에서 사이드바 상태만 관리한다.
4. ( + 그 다음 사이드바 컴포넌트에서 애니메이션 상태를 따로 추가했다.)
5. RTK 리팩토링 및 변수명들도 수정함.
const [sidebarOpen, setSidebarOpen] = useState<boolean>(false);
// SidebarWrapper or Close 클릭 시 side bar 닫기
const handletoggleSidebar = () => {
setSidebarOpen(!sidebarOpen);
// side bar를 닫을 때 setTimeOut 시간 후 sidebarWrapper를 없애주기
if (!sidebarOpen) {
setTimeout(() => {
dispatch(toggleSidebar());
}, 200); // 애니메이션의 지속 시간과 같게 설정하면 깜빡임 발생함
}
};
const Sidebar = styled.div<AnimationProps>`
width: 320px;
height: 909px;
align-items: center;
display: flex;
flex-direction: column;
position: absolute;
background-color: #141414;
animation: ${(props) => props.animation} 0.25s ease-out;
`;
사이드바 컴포넌트에서 따로 애니메이션을 관리하니 정상 동작함.