width: 768px 이상일 때는 hover하면 나타나는 메뉴를 나오게 하고
그 이하 (mobile size)일 때는 로고를 클릭하면 드롭다운 메뉴가 나오게 하려고 한다.
<DropDown> (1) 드롭다운 메뉴의 기준점: relative
<MenuBar> (2) 메뉴 리스트를 한 번에 담음 : absolute
<ul> (3) 메뉴 리스트
<li>1</li>
<li>2</li>
</ul>
</MenuBar>
</DropDown>
const DropDown = styled.button`
position: relative; (1)
width: 100px;
`;
const MenuBar = styled.div`
position: absolute; (2)
display:none; (4)
${DropDown}:active & { (5)
display: block;
}
${DropDown}:focus & { (5)
display: block;
}
`;
// 하지만 styled-component로 작성된 형태는 가능하지만
const DropDown = styled.div`
...
`
//다음과 같은 형태는 불가능했다.
const DropDown = () => {
return (
...)
}
//Layouts.tsx
export const BasicLayout = () => {
return (
<>
<DropdownHeader />
{window.outerWidth < 768 ? '' : <MenuBar />}
<Outlet />
<Footer />
</>
);
};
//LogoAndSearch.tsx
export const DropdownHeader = () => {
return (
<Vertical>
<LogoContainer>
<HomeLogo
margin={window.outerWidth < 768 ? '0' : RESPONSIVE.HEADER_MARGIN}
/>
{window.outerWidth < 768 ? <DropdownBar display='block' /> : ''}
</LogoContainer>
<Searchbar />
</Vertical>
);
};
//MenuBar.tsx
export const DropdownBar: React.FC<BarProp> = ({ display }) => {
return (
<Vertical>
<MenuContainer display={display}>
{mainMenu[0].list.map((el, idx) => (
<Main key={idx}>{el.title}</Main>
))}
</MenuContainer>
</Vertical>
);
};
DropdownBar 내부의 MenuContainer 컴포넌트의 위치를 absolute로 한다. Main 컴포넌트는 메뉴블럭 하나하나를 뜻하는데 만약 Main의 위치를 absolute로 한다면 모든 메뉴가 한 곳에 겹쳐 나오기 때문에 Main들을 묶어서 absolute prop을 가져줄 MenuContainer 컴포넌트가 필요한 것이다.
이제 클릭할 때마다 useState로 상태에 따라 display의 prop을 block / none으로 결정하면 드롭다운 메뉴가 활성화된다.
//LogoAndSearch.tsx
import {useState} from 'react';
interface ClickProp {
onClick?: () => void; (1)
}
export const DropdownHeader: React.FC<ClickProp> = () => { (1)
const [menuActive, setMenuActive] = useState<boolean>(false); (2)
const toggle = () => {setMenuActive(!menuActive)}; (3)
return (
<Vertical>
<LogoContainer onClick={toggle}> (4)
<HomeLogo
margin={window.outerWidth < 768 ? '0' : RESPONSIVE.HEADER_MARGIN}
/>
{window.outerWidth < 768 ? (
<DropdownBar display={menuActive ? 'block' : 'none'} />
) : (
''
)} (5)
</LogoContainer>
<Searchbar />
</Vertical>
);
};