처음 만난 리액트 문서


5.5 컴포넌트 추출

컴포넌트 합성과 반대로 복잡한 컴포넌트를 쪼개서 여러개의 컴포넌트로 나눌 수도 있습니다. 이러한 과정을 우리는 컴포넌트 추출(Extracting components) 이라고 부릅니다. 큰 컴포넌트에서 일부를 추출해서 새로운 컴포넌트를 만든다는 뜻이죠. 컴포넌트 추출을 잘 활용하게 되면 컴포넌트의 재사용성이 올라가게 됩니다. 왜냐하면 컴포넌트가 작아질수록 해당 컴포넌트의 기능과 목적이 명확해지고, props도 단순해지기 때문에 다른 곳에서 사용할 수 있을 확률이 높아지기 때문입니다. 그리고 재사용성이 올라감으로써 동시에 개발 속도도 향상됩니다. 아래에서 컴포넌트를 추출하는 과정을 하나하나씩 살펴보도록 하겠습니다.

function Comment(props) {
    return (
        <div className="comment">
            <div className="user-info">
                <img className="avatar"
                    src={props.author.avatarUrl}
                    alt={props.author.name}
                />
                <div className="user-info-name">
                    {props.author.name}
                </div>
            </div>

            <div className="comment-text">
                {props.text}
            </div>

            <div className="comment-date">
                {formatDate(props.date)}
            </div>
        </div>
    );
}

먼저 여기에 Comment라는 컴포넌트가 하나 있습니다. 이 컴포넌트는 댓글을 표시하기 위한 컴포넌트로써, 내부에 작성자의 프로필 이미지와 이름, 그리고 댓글 내용과 작성일을 포함하고 있습니다. 이제 이 컴포넌트에서 하나씩 컴포넌트를 추출해보도록 하겠습니다. 먼저 첫 번째는 Avatar추출입니다. Comment컴포넌트에서는 <img>태그를 사용하여 사용자의 프로필 이미지를 표시하고 있습니다. 이 부분을 추출해서 Avatar라는 별도의 컴포넌트로 만들어 보겠습니다.

function Avatar(props) {
    return (
        <img className="avatar"
            src={props.user.avatarUrl}
            alt={props.user.name}
        />
    );
}

추출된 Avatar컴포넌트는 이런 모습이 될 것입니다. 그리고 props에 기존에 사용하던 author 대신 조금 더 보편적인 의미를 갖고 있는 user를 사용하였습니다. 보편적인 단어를 사용하는 것은 재사용성 측면을 고려하는 것이라고 보면 됩니다. 다른 곳에서 이 컴포넌트를 사용할 때도 props에 들어갈 속성들이 의미상 큰 차이 없이 사용할 수 있게 하기 위함인 것이죠. 자, 이렇게 추출된 Avatar컴포넌트를 이제 실제로 Comment컴포넌트에 반영해봐야 되겠죠?

function Comment(props) {
    return (
        <div className="comment">
            <div className="user-info">
                <Avatar user={props.author} />
                <div className="user-info-name">
                    {props.author.name}
                </div>
            </div>

            <div className="comment-text">
                {props.text}
            </div>

            <div className="comment-date">
                {formatDate(props.date)}
            </div>
        </div>
    );
}

추출된 Avatar컴포넌트가 적용된 모습입니다. Avatar라는 이름의 컴포넌트로 교체되고 나니 조금 더 코드의 가독성이 높아진 것 같죠? 이제 다음 단계로 사용자 정보를 담고 있는 부분을 추출해보도록 하겠습니다.

function UserInfo(props) {
    return (
        <div className="user-info">
            <Avatar user={props.user} />
            <div className="user-info-name">
                {props.user.name}
            </div>
        </div>
    );
}

위 코드는 사용자 정보를 담고 있는 부분을 UserInfo라는 컴포넌트로 추출한 것입니다. 아까 처음에 추출했던 Avatar컴포넌트도 여기에 함께 추출된 것을 볼 수 있습니다. 그리고 역시 propsauthor 대신 조금 더 보편적인 의미를 갖고 있는 user를 사용하였습니다. 그럼 이제 추출된 UserInfo컴포넌트를 Comment컴포넌트에 반영을 해야겠죠?

function Comment(props) {
    return (
        <div className="comment">
            <UserInfo user={props.author} />
            <div className="comment-text">
                {props.text}
            </div>
            <div className="comment-date">
                {formatDate(props.date)}
            </div>
        </div>
    );
}

UserInfo컴포넌트를 반영하면 이렇게 됩니다. 코드가 처음에 비해서 훨씬 더 단순해졌죠? 지금까지 추출한 컴포넌트들의 구조를 그림으로 나타내면 다음과 같습니다.

Extracting component

Comment컴포넌트가 UserInfo컴포넌트를 포함하고 있고, UserInfo컴포넌트가 Avatar컴포넌트를 포함하고 있는 구조입니다. 지금까지 추출한 것 이외에도 추가적으로 Comment 글과 작성일이 나오는 부분도 별도의 컴포넌트로 추출이 가능합니다. 컴포넌트를 어느정도 수준까지 추출하는 것이 좋은지에 대한 정해진 기준은 없습니다. 하지만 기능 단위로 구분하는 것이 좋고, 나중에 곧바로 재사용이 가능한 형태로 추출하는 것이 좋습니다. 지금 살펴본 예제에서 추출한 Avatar컴포넌트나 UserInfo컴포넌트는 다른 웹사이트를 만들때도 충분히 재사용이 가능할 것입니다. 그리고 앞에서 말한 것처럼 재사용 가능한 컴포넌트들을 많이 갖고 있을수록 개발 속도가 굉장히 빨라지게 됩니다.


마지막 업데이트: 2025년 08월 21일 08시 08분

이 문서의 저작권은 이인제(소플)에 있습니다. 무단 전재와 무단 복제를 금합니다.

On this page

  • 5.5 컴포넌트 추출