청년을 구해줘!에서 메인 페이지 컴포넌트를 만들고 있다. 여기에 사이드바가 들어간다.
지금 만들어둔 건 최적화를 하지 않은 상태라서 번쩍번쩍 불이 자주 난다. 오늘 저녁에 할 작업 중 하나이다 (행복하다!)
처음에 바닐라 JS에서 리액트로 넘어올 때 어떤 걸 컴포넌트로 만들어야 할지 고민이 많았다. 내가 보기엔 그냥 다 한 덩어리 같았다. 나와 같은 고충을 겪고 있을 사람들을 위해 하나를 만들기 위해 작게 세분화한 방법을 적어보겠다.
사이드바를 보았을 때 든 생각이다.
이것을 기반으로 컴포넌트를 기획하였다.
color
, 굵기 font-weight
, 크기 font-size
, 버튼 방향, 밑줄 굵기 등을 props로 받는다.한 줄을 OptionItem
이라고 이름을 지었다. OptionItem
을 모으면 OptionList
가 된다.
const OptionItem = ({
children,
fontSize = '1rem',
fontWeight = 'regular',
underlineHeight = '0',
direction = null,
disabled = false,
isGetReady = false,
}: OptionItemProps) => {
props 하나씩 설명해보자면,
OptionItem
사이에 들어간다.underlineWidth
로 단어를 바꾸어도 괜찮을 거 같다.생각해낸 방식은 2가지이다.
<button>
// span
// button image
</button>
둘 다 될 거 같은데, input 만들 때 relative 사용했던 기억이 있어서 복습하고자 하는 마음에 2번을 선택했다.
OptionItem
을 모아서 OptionList
를 만든다.
return (
<StyledOptionList ref={sidebarRef} isOpen={isOpen}>
<StyledSidebarHeader>
<StyledCloseContainer onClick={() => onSidebarOpen(false)}>
<Close />
</StyledCloseContainer>
청년을 구해줘!
</StyledSidebarHeader>
{children} -------------->>> 여기에 OptionItem들이 모여있다.
</StyledOptionList>
);
ref
를 사용하면 편하다. 화면에 click EventListener를 단다. 화면에 클릭 이벤트가 발생되었을 때 sidebarRef
의 바깥쪽이 클릭 되면 return onSidebarOpen(false);
를 한다.
const OptionList = ({ children, onSidebarOpen, isOpen }: OptionListProps) => {
const sidebarRef = useRef<HTMLElement>(null);
const onClickOutside = (event: Event) => {
if (!sidebarRef.current?.contains(event.target as Node)) {
return onSidebarOpen(false);
}
};
useEffect(() => {
document.addEventListener('click', onClickOutside, true);
return () => {
document.removeEventListener('click', onClickOutside, true);
};
});
디자인에 있는 option을 Array로 저장한 후에 OptionItem
의 props로 전달하여 보여주면 된다.
return (
<OptionList onSidebarOpen={onSidebarOpen} isOpen={isOpen}>
{userSetting.map((option) => (
<Link key={`${option.name}-${option.link}`} to={option.link}>
<OptionItem
fontSize={option.fontSize}
fontWeight={option.fontWeight}
underlineHeight={option.underlineHeight}
direction={option.direction}
disabled={option.disabled}
isGetReady={option.isGetReady}
>
{option.name}
</OptionItem>
</Link>
))}
맨 윗쪽에 있는 컴포넌트가 눌렸을 때 하단에 있는 컴포넌트를 안 보이게 해주면 된다.
{titleClicked && (
<div>
{tails.map((tail) => (
<Link key={`${tail.name}-${tail.link}`} to={tail.link}>
<OptionItem
fontSize={tail.fontSize}
fontWeight={tail.fontWeight}
underlineHeight={tail.underlineHeight}