부캠에서 children에 대해서 세션을 들었던 적이 있었는데,
그때는 이걸 사용 할 일이 많을까? 너무 복잡해 보이는데 ... 라고 생각만하고 지나쳤었다.
회사에서 프로젝트를 하다보니 그동안과는 다르게 많은 페이지를 다루면서 비슷한 내용을 다루는 페이지 별 공용 레이아웃이 필요하다는 것을 느꼈다.
project : commerce web app
stack : #React
#styled-component
#TypeScript
#Zustand
상단에 뒤로가기 버튼과 장바구니가 있는 공용 TopBar 컴포넌트가 위치하고 기간 선택하는 셀렉트박스까지 공용 사용 부분이었다.
children으로 선택한 기간에 대한 리스트를 뿌려주는것으로 작업!
/*children 받아서 사용하는 레이아웃 컴포넌트*/
interface Props {
title: string;
children: ReactNode;
}
const OrderLayout = ({ title, children }: Props) => {
return (
<PageWrap>
<TopBar />
<Title>{title}</Title>
<PeriodWrap>
<PeriodSelect>
<Period>최근 3개월</Period>
<Period>최근 6개월</Period>
<Period>최근 1년</Period>
</PeriodSelect>
</PeriodWrap>
<ListContainer>{children}</ListContainer>
</PageWrap>
);
};
OrderLayout
컴포넌트를 생성ListContainer
내에 List가 들어갈 예정으로 {children}
자리를 만들어 주었다.select
값은 전역상태관리를 통해 cildren 리스트 뿌리는 곳에서 사용 할 예정!ReactNode
로 사용!import React 사용 여부!
children: ReactNode
=> import React, { ReactNode } from "react";
children: React.ReactNode
=> import React from "react";
- ReactNode는 react안에 포함된 것으로 편한대로 사용
/*레이아웃 컴포넌트 사용하는 페이지*/
const OrderHistory = () => {
useEffect(() => {
//... listData 가져오기 생략
}, [])
return (
<OrderLayout title="주문 내역 조회">
{listData.length ? (
listData.map((data) => (
<OrderList key={data.id} productdata={data}/>
)
) : (
<EmptyView desc="상품이 없어요" />
)}
</OrderLayout>
);
};
<OrderLayout> {이 부분에 들어가는 것이 children} </OrderLayout>
EmptyView
컴포넌트를 보여주고, 데이터가 있을 땐 map시켜준다.데이터 교체가 아닌 children으로 한 이유 ?
리스트의 카드레이아웃이 페이지별로 조금씩 달랐기 때문에 그 부분은 공통으로 사용하기 보단 children으로 사용하는게 좋을 것 같다고 판단하였다.
/*children 받아서 사용하는 toggle 컴포넌트*/
const Toggle = ({ title, children }: Props) => {
const [isOpen, setIsOpen] = useState(false);
const handleToggle = (e: any) => {
setIsOpen((prev) => !prev);
};
return (
<Toggle>
<Btn onClick={handleToggle}>
{title}
<ToggleArrow isOpen={isOpen} />
</Btn>
<Content isOpen={!isOpen}>{children}</Content>
</Toggle>
);
};
/*toggle 컴포넌트 사용하는 페이지*/
<InfoToggle title="판매자 안내">{"내용"}</InfoToggle>
<InfoToggle title="상품 고시정보">{"내용"}</InfoToggle>
isOpen={true}
일 때에만 보이도록 해주었다.<OrderLayout
title="페이지 제목"
>
<ListContainer>
<OrderToggle
title="구매한 상품"
desc={"내용"}
defaultOpen={true}
>
<>내용 컴포넌트</>
</OrderToggle>
<OrderToggle
//... 생략
>
<>내용 컴포넌트</>
</OrderToggle>
<OrderToggle
//... 생략
>
<>내용 컴포넌트</>
</OrderToggle>
{/* 생략 */}
</ListContainer>
</OrderLayout>
OrderLayout
컴포넌트의 cildren으로 orderToggle
컴포넌트를 사용하고 토글의 내용컴포넌트를 cildren으로 넘겨주었다.공통으로 사용하는 페이지가 5개인데 한번 레이아웃컴포넌트를 잡아두니, 재사용 할 수 있어서 빠르게 작업을 할 수 있었다.
그리고 가장 좋은점은 수정사항이 있을 때 해당 레이아웃컴포넌트만 수정하면 되는 부분이다.
페이지 레이아웃을 만들어 보니 공용으로 사용하는 컴포넌트 내에서 children을 사용하면 더욱 다양하게 공용컴포넌트로 만들어 둘 수가 있겠다는 생각도 하였고, 그래서 toggle list
도 children을 사용한 컴포넌트화 시킬 수 있었다.
그동안 일반 컴포넌트로 작업 한 부분에서도 children 사용하면 좋을 것 같은데? 싶은 부분들도 눈에 보여서, 해당 부분은 나중에 리팩토링 때 다듬고 싶은 부분이다.
(children에대해 검색하다 보니 카카오 기술블로그 21년 글도 찾게되어서 좀더 다양하게 사용할 수 있는 방법을 알아두면 좋을 것 같아서 레퍼 첨부!)
react children with typescript
카카오 엔터 기술블로그 - React Children과 친해지기
공부하며 정리&기록하는 ._. 씅로그