Children API 활용하여 자식 Element 제어

CharmingL·2024년 5월 9일
0

Figure Out

목록 보기
3/5
post-thumbnail

Children 활용하여 자식 사이에 Divider 추가

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 API

Children. 치면 나오는 함수들은 다음과 같다.

count / forEach / map / toArray 모두 익숙한 이름이다

  • count는 자식 수를 세어 알려주는 함수
  • forEachmap은 자식을 조회해가며 작업을 할 수 있도록 하는 함수
  • 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-componentsCSS 만으로도 충분히 구현할 수 있는 스타일링이었다.
참고)

/* DropDownMenu를 감싸고 있는 Container 내 */
& > button {
    border-top: 2px solid orange;
}
& > button:first-child {
    border: 0;
}

개인적으로 스타일링에 JS로 제어하기 보다 웬만하면 CSS로 구현하는게 좋다고도 생각하지만
Children API를 한번도 써본 적이 없어 작성해본 포스팅..!
이젠 children도 효율적으로 사용하고 싶을 때 잘 활용하면 좋을 것 같다

profile
내 빈틈을, 조금씩 천천히!! ٩(•᎑•)✦

0개의 댓글