React 14. Composition

@t189216·2024년 3월 8일

😎 프론트엔드

목록 보기
26/31

Composition


리액트에서 Composition 은 여러 개의 컴포넌트를 합쳐서 새로운 컴포넌트를 만드는 것을 말합니다.

복잡한 컴포넌트를 쪼개서 여러 개의 컴포넌트를 만들고, 만든 컴포넌트들을 조합해서 새로운 컴포넌트를 만들자 !

여러 개의 컴포넌트들을 어떻게 조합하느냐에 따라 사용기법이 나뉩니다.

Containtment

하위 컴포넌트를 포함하는 형태의 합성 방법을 말합니다. Sidebar나 Dialog 같은 Box형태의 컴포넌트는 자신의 하위 컴포넌트를 미리 알 수 없습니다. 해당 컴포넌트를 사용하는 개발자가 어떤 것을 넣느냐에 따라 하위 컴포넌트가 달라지기 때문입니다.

Containtment 을 사용하려면 children이라는 prop을 사용해서 조합하면 됩니다.

function FancyBorder(props) {
    return (
        <div className={'FancyBorder FancyBorder-' + props.color}>
            {props.children}
        </div>
    );
}

리액트에서는 하위 컴포넌트를 props.children으로 하나로 모아서 제공해 줍니다.

FancyBorder 사용 예시 #1

function WelcomeDialog(props) {
    return (
        <FancyBorder color="blue">
            <h1 className="Dialog-titile">
                어서오세요
            </h1>
            <p className="Dialog-message">
                우리 사이트에 방문하신 것을 환영합니다!
            </p>
        </FancyBorder>
    );
}

여러 개의 children 집합이 필요한 경우

function SplitPane(props) {
    return (
        <div className="SplitPane">
            <div className="SplitPane-left">
                {props.left}
            </div>
            <div className="SplitPane-right">
                {props.right}
            </div>
        </div>
    );
}

function App(props) {
    return (
        <SplitPane
            left={
                <Contacts />
            }
            right={
                <Chat />
            }
        />
    );
}

Specialization

범용적인 개념을 구별이 되게 구체화 하는 것을 Specialization 이라고 합니다. 리액트에서는 합성(Composition)을 사용하여 Specialization 을 구현합니다.

범용적으로 쓸 수 있는 컴포넌트를 만들어 놓고, 이를 특수화 시켜서 컴포넌트를 사용하는 Composition 방법입니다.

Specialization 예시

function Dialog(props) {
    return (
        <FancyBorder color="blue">
            <h1 className="Dialog-title">
                {props.title}
            </h1>
            <p className="Dialog-message">
                {props.message}
            </p>
        </FancyBorder>
    );
}

function WelcomeDialog(props) {
    return (
        <Dialog
            title="어서오세요"
            message="환영합니다!"
        />
    );
}

Dialog 컴포넌트를 사용하는 WelcomeDialog 컴포넌트입니다. Dialog 컴포넌트에는 title과 message라는 두 가지 props를 가지고 있는데, 다이얼로그에 나오는 제목과 메시지를 의미합니다.

제목과 메시지를 어떻게 사용하느냐에 따라서 경고 다이얼로그가 될 수도 있고, 인사 다이얼로그가 될 수도 있습니다.

Containtment와 Specialization을 같이 사용하기

Containtment를 위해 props.children을 사용하고, Specialization을 위해 직접 정의한 props를 사용해봅시다.

function Dialog(props) {
    return (
        <FancyBorder color="blue">
            <h1 className="Dialog-title">
                {props.title}
            </h1>
            <p className="Dialog-message">
                {props.message}
            </p>
            {props.children}  // Containtment를 위해 추가
        </FancyBorder>
    );
}

Containtment를 위해 props.children를 추가했습니다. 이를 통해 하위 컴포넌트가 다이얼로그 하단에 렌더링됩니다.

function SignupDialog(props) {
    const [nickname, setNickname] = useState('');

    const handleChange = (event) => {
        alert(`어서오세요, ${nickname}님!`);
    }

    return (
        <Dialog
            title="게시판"
            message="닉네임을 입력해주세요.">
            <input
                value={nickname}
                onChange={handleChange}/>
            <button onClick={handleSignup}>
                가입하기
            </button>
        </Dialog>
    );
}

Dialog 컴포넌트를 사용하는 SignupDialog 컴포넌트입니다. Specialization을 위한 props인 title, message에 값을 넣어주고 있으며, 사용자로부터 닉네임을 입력받고 가입을 하도록 유도하기 위해 input, button 태그가 있습니다. 두 개의 태그는 모두 props.children으로 전달되어 다이얼로그에 표시됩니다.

Inheritance


Composition와 대비되는 개념으로, 상속이라는 뜻을 가집니다. 리액트에서는 다른 컴포넌트로부터 상속받아서 새로운 컴포넌트를 만드는 것을 고려해볼 수 있습니다.

하지만 리액트를 개발한 메타에서 수천 개의 리액트 컴포넌트를 사용했지만, 상속을 사용하여 컴포넌트를 만드는 것을 추천할 사용 사례를 찾지 못했다고 합니다. 리액트에서는 상속보단 컴포지션을 사용해서 개발하는 것이 더 좋은 방법입니다.

profile
Today I Learned

0개의 댓글