컴포넌트에서 다른 컴포넌트 담기
const App = () => {
<Parent>
<Child />
<Parent>
}
const App = () => {
<SplitPane
left={
<Contacts />
}
right={
<Chat />
}
/>
}
const SplitPane = (props) => (
<section>
<div>
{props.left}
</div>
<div>
{props.right}
</div>
<section>
)
합성을 사용하여 컴포넌트 간에 코드를 재사용하는 것이 좋습니다.
const AwesomeButton = () => (
<button>awesome</burron>
)
const AwesomeUI = () => {
<Layout>
<AwesomeButton />
</Layout>
}
const AwesomeConponent = () => {
const { data, isLoading, isError } = useAwesomeFetch();
if(isError) return <div>error...!<div
if(isLoading) return <div>loading...!<div>;
return <div>{data}<div>;
}
const AwesomeUI = () => {
<ErrorBoundary fallback={<div>error...!</div>}>
<Suspense fallback={<div>loading...!</div>}>
<AwesomeComponent />
</Suspense>
</ErrorBoundary>
}
<select>
<option value="value1">value1</option>
<option value="value2">value2</option>
<option value="value3">value3</option>
</select>
const ReviewFilterModal = () => {
const [isOpen, openModal, closeModal] = useModal();
return (
<>
<AwesomeButton onClick={openModal}>필터<AwesomeButton>
{isOpen && (
<Portal>
<Backdrop onClick={closeModal} />
<AwesomeModalBox>
<Header>
<div>리뷰 검색 필터<div>
<Close>x<Close>
<Header>
<ModalContent>
<AwesomeModalBox>
</Portal>
)}
<>
)
}
const Modal = ({ trigger, title }) => {
const [isOpen, openModal, closeModal] = useModal();
return (
<>
{trigger}
{isOpen && (
<Portal>
<Backdrop onClick={closeModal} />
<AwesomeModalBox>
<Header>
{title}
<Close>x<Close>
<Header>
<ModalContent>
<AwesomeModalBox>
</Portal>
)}
<>
)
}
const ModalTrigger = ({ children, style }) => (
<button style={style || defaultTriggerStyle}>{children}<button>
)
const ModalBackdrop = ({ style }) => (
<div aria-hidden style={style || defaultBackdropStyle}><div>
)
const ModalClose = ({ style }) => (
<button style={style || defaultCloseStyle}><button>
)
const ModalContent = ({ style }) => (
<div style={style || defaultContentStyle}><div>
)
const Modal = ({ children }) => children
<Modal>
<ModalTrigger />
<ModalBackdrop />
<ModalContent>
<ModalClose />
<ModalContent>
<Modal>
<Modal>
<ModalTrigger>필터<ModalTrigger>
<Portal>
<ModalBackdrop />
<ModalContent>
<Flex>
<Title>리뷰 검색 필터</Title>
<ModalClose>X<ModalClose>
<Flex>
<FilterSection>
<ModalContent>
<Portal>
<Modal>
const Modal = ({ children }) => {
const [isOpen, openModal, closeModal] = useModal();
return (
<ModalProvider value={{ isOpen, openModal, closeModal }}>
{children}
<ModalProvider>
)
}
const ModalTrigger = ({ children, style }) => {
const { openModal } = useModalContext();
return (
<button style={style || defaultTriggerStyle} onClick={openModal}>{children}<button>
)
}
const ModalContent = ({ style }) => (
const { isOpen } = useModalContext();
return isOpen ? (<div style={style || defaultContentStyle}><div>): null
)
const Modal = ({ children }) => {
const [isOpen, openModal, closeModal] = useModal();
return (
<ModalProvider value={{ isOpen, openModal, closeModal }}>
{children}
<ModalProvider>
)
}
Modal.Trigger = ModalTrigger
Modal.Backdrop = ModalBackdrop
Modal.Close = ModalClose
Modal.Content = ModalContent
<Modal>
<Modal.Trigger>필터<Modal.Trigger>
<Portal>
<Modal.Backdrop />
<Modal.Content>
<Flex>
<Title>리뷰 검색 필터</Title>
<Modal.Close>X<Modal.Close>
<Flex>
<FilterSection>
<Modal.Content>
<Portal>
<Modal>
const Modal = ({ children }) => {
const [isOpen, openModal, closeModal] = useModal();
return (
<ModalProvider value={{ isOpen, openModal, closeModal }}>
{children}
<ModalProvider>
)
}
const ReviewFilterModal = () => {
const [isOpen, setOpen] = useModal(false)
const safetyClose = () => {
setOpen(confirm('닫으면 필터가 적용되지 않습니다. 닫으시겠습니까?'))
}
<Modal open={isOpen} onOpenChange={setOpen}>
...기존 코드
<Modal.Close onClick={safetyClose}>X<Modal.Close>
<Modal>
}
// open props를 통해 최종적으로 사용될 상태 결정
const Modal = ({ children, open }) => {
const [isOpen, openModal, closeModal] = useModal();
const composeIsOpen = open ?? isOpen
return (
<ModalProvider value={{ isOpen: composeIsOpen, openModal, closeModal }}>
{children}
<ModalProvider>
)
}
const ModalClose = ({ children, style }) => (
const { closeModal } = useModalContext();
const composedOnClick = composeFunctions(onClick, closeModal);
<button style={style || defaultCloseStyle} onClick={composedOnClick}>{children}<button>
)
지금까지 합성 컴포넌트 패턴에 대해서 알아봤는데요. 모든 디자인 패턴이 그렇듯 합성 컴포넌트 패턴 또한 장단점을 가지고 있고, 사용하는 이유를 명확하게 알게되었던 시간 같습니다. 단점으로 나왔던 코드의 길이가 늘어난다는 것의 개인적인 의견을 말해보자면 클린 코드는 짧은 코드가 아니라 읽기 쉬운 코드라는 말이 있는 만큼 코드의 길이보다는 가독성이 더 중요하다고 생각해 저는 현재 진행하고 있는 프로젝트에 적용해볼 예정인데요. 현재 Modal을 구현하고 있는 방법과는 살짝 달라서 저한테 맞는 방식으로 변경해서 적용해볼 예정입니다.