interface Props {
align?: Align;
direction?: Direction;
size?: Size | Size[];
split?: React.ReactNode;
wrap?: boolean;
}
const Space = ({
align = "center",
children,
direction = "horizontal",
size = "middle",
split,
wrap,
}: React.PropsWithChildren<Props>) => {
return <div className={className}>{children}</div>;
};
export default Space;
Ant Design에 있는 Space 컴포넌트를 보고 구조를 잡아봤다. 대부분 CSS와 관련된 컴포넌트라 어렵지 않게 구현이 가능했지만, children 사이사이에 split
child를 껴(?) 넣어주는 부분은 조금 생소했다. 이 부분에 대해 알아보자.
split props로 <Divider />
를 넘겨준 모습이다.
split에 ReactNode에 해당하는 Element를 props로 넘겨주면 Children 사이사이에 split에 들어온 ReactNode를 넣어준다.
React.Children에는 count
, forEach
, map
, toArray
, only
5가지 메서드가 있는데, 각 메서드의 동작은 여기에서 확인할 수 있다.
첫 번째로 Children을 배열로 만드는 toArray 메서드를 사용해서 children 배열을 만들고, 이를 순회하면서 각각의 children 사이에 split element를 껴주면 될 것 같다는 생각을 했다.
React.Children.toArray(children).reduce<React.ReactNode[]>((acc, cur, i) => {
if (i === 0) {
return acc.concat(cur);
} else {
return acc.concat([split, cur]);
}
}, []);
결과
동작은 잘 되나 유니크한 key props이 필요하다는 warning이 뜬다. 이를 해결하기 위해 toArray()
대신 map()
사용하는 것으로 수정하고, key prop을 하나씩 추가해주기로 했다.
React.Children.map(children, (child, i) =>
i === 0 ? (
child
) : (
<React.Fragment key={child?.toString()}>
<>{split}</>
<>{child}</>
</React.Fragment>
)
);
결과
key props warning 없이 잘 렌더링 되었다.
Ant Design에 있는 컴포넌트들을 하나씩 만들어 보기로 했다. 간단한 것 부터 하나씩 만들어가는데 Space에서 split props로 내려주는 것이 생소하기도 하고, React.Children
을 존재만 알고 제대로 알지는 못해서 내용을 같이 정리한다.
React.Children
말고도 최상위 API로 React.Component
라던지, React.cloneElement
등 여러가지 API들이 있지만 아직은 제대로 사용해보진 못했어서 다양한 Library들을 만들어보면 조금씩 사용해볼 수 있지 않을까 기대해본다.