DropDownMenu내 각 메뉴들 사이에 구분선을 넣어야 한다. 내가 작성한 DropDownMenu 메뉴 구조는 다음과 같다.
// DropDownMenu 정의 부분
export const DropDownMenu = ({ children }: PropsWithChildren) => {
return (
<Container>{children}</Container>
);
};
const MenuItem = ({
children,
...props
}: ButtonHTMLAttributes<HTMLButtonElement>) => {
return <MenuItemWrapper {...props}>{children}</MenuItemWrapper>;
};
DropDownMenu.MenuItem = MenuItem;
그리고 이를 참조하는 상위 컴포넌트에서는 DropDownMenu의 Item에 해당하는 버튼의 props를 정의해서 사용한다.
// DropDownMenu를 사용하는 상위 컴포넌트
<MypageListProfile>
...
<DropDownMenu>
<DropDownMenu.MenuItem onClick={() => signOut()}>로그아웃</DropDownMenu.MenuItem>
<DropDownMenu.MenuItem onClick={() => withdrawal()}>회원탈퇴</DropDownMenu.MenuItem>
</DropDownMenu>
...
</MypageListProfile>
일일이 상위 컴포넌트에서 divider 컴포넌트를 정의해서 사용하는 방식은 귀찮고, 이후에 divider에 대한 스타일 변경이 존재했을 때 일일이 바꿔줘야 하는 번거로움이 있어 DropDownMenu
내부에서 공통으로 처리해주는 게 낫다고 판단했다.
"0번째를 제외한 인덱스의 MenuItem 컴포넌트 위에 divider가 들어가면 된다"
라는 점을 이용하여 Children API
를 활용해보기로 했다.
Children
은 우리에게 익숙한 children
props로 넘어오는 jsx 컴포넌트들을 제대로 활용하기 위해 제공되는 api라고 한다
그동안 children props를 받아 원하는 곳에 바로 렌더링만 해봤는데, 이번 기회에 써보기로~
Children.
치면 나오는 함수들은 다음과 같다.
count
/ forEach
/ map
/ toArray
모두 익숙한 이름이다
count
는 자식 수를 세어 알려주는 함수forEach
와 map
은 자식을 조회해가며 작업을 할 수 있도록 하는 함수toArray
는 자식 요소들에 필터링이나 정렬과 같은 작업을 취할 수 있도록 자식을 배열로 받는 함수일 것이다! 맞네~
그렇다면 only
는?
자식이 하나의 React Element만 가지는지를 확인하고
맞다면 해당 컴포넌트를, 그 외의 경우에는 Error
를 반환하는 함수라고 한다.
이중에서 내가 사용할 건 map
!
사용법은 간단하다.
첫번째 인자로 전달받은 자식 children props
을 넣어주고,
두번째 인자로 Array.map(callback)
의 callback 그대로 넣어주면 된다!
<>
{Children.map(children, callback)}
</>
이제 이를 활용하여 구분선을 넣어보자.
map의 callback은 조회하면서 원소 뿐 아니라 해당 원소의 인덱스와 기존 배열 정보도 함께 얻어올 수 있다.
map(ele, (ele, idx, arr)=>{})
나는 자식의 인덱스를 활용하여, 첫번째를 제외한 컴포넌트 상단에 Divider
컴포넌트를 추가로 렌더링하도록 작성했다.!
export const DropDownMenu = ({ children }: PropsWithChildren) => {
return (
<Container>
{Children.map(children, (child, i) => (
<>
{i !== 0 && <Divider />}
{child}
</>
))}
</Container>
);
};
해결!
사실 오늘 한 작업은 styled-components
내 CSS
만으로도 충분히 구현할 수 있는 스타일링이었다.
참고)
/* DropDownMenu를 감싸고 있는 Container 내 */
& > button {
border-top: 2px solid orange;
}
& > button:first-child {
border: 0;
}
개인적으로 스타일링에 JS로 제어하기 보다 웬만하면 CSS로 구현하는게 좋다고도 생각하지만
Children API를 한번도 써본 적이 없어 작성해본 포스팅..!
이젠 children도 효율적으로 사용하고 싶을 때 잘 활용하면 좋을 것 같다