React.js 지식 - React.js에서 컴포넌트가 나누어져야 하는 이유

이유승·2024년 3월 9일
0

React.js 지식

목록 보기
5/8

React.js는 '컴포넌트' 기반의 JavaScript 라이브러리입니다.

'컴포넌트' 기반이라는 것은, UI를 구현할 때 독립적이고 재사용 가능한 컴포넌트들로 나누어서 개발하는 것을 뜻합니다. 컴포넌트를 나누는 이유는 관심사의 분리, 코드 재사용성 증가, 유지보수의 용이성 향상 때문입니다.

컴포넌트를 '잘' 나누게 되면, 하나의 컴포넌트는 명확한 목적과 기능을 가지고 전체적인 어플리케이션의 짜임새가 잘 만들어지며 전반적인 관리가 수월해집니다.

1. 컴포넌트는 어떻게 나누어야 하는가?

그렇다면 React.js에서 컴포넌트는 어떻게 나누어져야 할까. 대략적으로 아래 원칙들을 준수하면 됩니다.

각각의 컴포넌트들은 '단일 책임 원칙'을 지킬 것.

복수의 장소에서 사용될 수 있는 UI적 요소들은 별로의 컴포넌트로 분리하여 '재사용'이 가능하도록 할 것.

여러 기능을 수행하는 컴포넌트는 하나의 기능을 수행하는 하위 컴포넌트들로 분해해서 관리가 용이하도록 할 것.

단일 책임 원칙(Single Responsibility Principle, SRP)

  • 간단하게 말하자면 "한 클래스(또는 모듈, 함수 등)는 오직 하나의 책임만 가져야 한다"는 것. 책임이라는 것은 기능 등을 뜻합니다.

  • 자세하고 복잡한 부분까지 말하자면.. 소프트웨어 엔지니어링에서 언급되는 SOLID 원칙 중 하나로 객체 지향 프로그래밍 및 시스템 설계에 널리 적용되는 개념이라고 합니다.

  • SRP 원칙에 의거하여 구현된 클래스, 모듈, 함수, 컴포넌트 등은 다른 클래스나 컴포넌트 등과의 결합도가 낮아지며, 시스템 전체의 유연성과 확장성이 향상시킬수 있고 (하나를 변경했을 때, 다른 곳에 미치는 영향이 적거나 없기 때문), 또 테스트해야 할 동작이 명확하고 제한적이 되어 테스트의 용이성이 상승한다고 합니다.

  • SOLID 원칙?
    객체 지향 프로그래밍과 디자인 패턴에서 좋은 코드 설계를 위한 기본적인 지침으로 널리 인정받고 있는, 소프트웨어 개발자 로버트 C. 마틴(Robert C. Martin)에 의해 소개되었으며, 유지보수가 용이하고 확장 가능하며 이해하기 쉬운 소프트웨어 시스템을 개발하기 위한 기본 원칙입니다. SOLID는 다음 다섯 가지 원칙의 첫 글자를 따서 만든 약어입니다.

    단일 책임 원칙 (Single Responsibility Principle)

    한 클래스는 하나의 책임만 가져야 합니다. 이 원칙은 클래스를 변경하는 이유는 단 하나여야 함을 의미합니다. 이를 통해 클래스가 너무 많은 기능을 갖지 않도록 하며, 각 클래스가 변경에 대한 영향을 최소화합니다.

    개방-폐쇄 원칙 (Open-Closed Principle)

    소프트웨어 개체(클래스, 모듈, 함수 등)는 확장에는 열려 있어야 하지만 변경에는 닫혀 있어야 합니다. 즉, 기존의 코드를 변경하지 않고도 기능을 확장할 수 있어야 합니다. 이를 통해 변경에 따른 위험과 비용을 줄일 수 있습니다.

    리스코프 치환 원칙 (Liskov Substitution Principle)

    하위 클래스는 언제나 자신의 상위 클래스로 교체될 수 있어야 합니다. 이 원칙은 상속을 사용할 때, 하위 클래스가 상위 클래스의 성격과 동작을 왜곡하지 않고 확장해야 함을 의미합니다. 이는 다형성을 올바르게 사용하는 데 중요한 지침입니다.

    인터페이스 분리 원칙 (Interface Segregation Principle)

    한 클래스는 자신이 사용하지 않는 인터페이스는 구현하지 말아야 합니다. 클라이언트는 그들이 사용하지 않는 메서드에 의존하도록 강제되어서는 안 됩니다. 이 원칙은 인터페이스가 너무 크고 포괄적이지 않도록 하여, 클래스가 필요하지 않은 기능을 구현하도록 강제하는 것을 방지합니다.

    의존성 역전 원칙 (Dependency Inversion Principle)

    고수준 모듈은 저수준 모듈에 의존해서는 안 되며, 둘 다 추상화에 의존해야 합니다. 추상화는 세부 사항에 의존해서는 안 되며, 세부 사항은 추상화에 의존해야 합니다. 이 원칙은 시스템의 결합도를 줄이고, 유연성과 재사용성을 증가시키는 데 도움이 됩니다.



2. 컴포넌트를 나누었을 때의 장점과 단점

우선 알아두어야 할 것은, 컴포넌트를 무조건 나눈다고 해서 다 좋은 것이 아니라는 점입니다. 컴포넌트가 나뉘어졌을 때의 장단점은 아래와 같습니다.

컴포넌트 분리의 장점

코드의 재사용성과 가독성이 증가하고, 복잡한 로직을 더 쉽게 관리할 수 있습니다. 또한, 개별 컴포넌트를 테스트하기 용이해져 전체 애플리케이션의 안정성이 향상됩니다.

컴포넌트 분리의 단점

각각의 컴포넌트들이 서로 어떤 관계이고, 무슨 영향을 주고받는지 파악하는게 어려워집니다. 데이터가 어느 경로를 거치면서 변화를 겪는지 알기 어려워집니다. 하나의 컴포넌트가 사실상 특정 컴포넌트 하위에서만 사용될 수 있는 역할에 국한될 수 있습니다.



3. 컴포넌트 나누기의 예시

예를 들어, 상품 상세 페이지를 구현할 때 '상품 설명', '가격 표시', '수량 선택' 등의 각 기능을 별도의 컴포넌트로 분리할 수 있습니다. 이렇게 하면 각 컴포넌트는 자신의 역할에만 집중할 수 있으며, 예를 들어 '가격 표시' 컴포넌트는 다른 페이지에서도 재사용될 수 있습니다.

const ProductDetailPage = ({ product }) => {

	(...)

    return (
        <div>
            <ProductDescription description={description} />
            <ProductPrice price={price} discount={discount} />
            <QuantitySelector onQuantityChange={handleQuantityChange} />
        </div>
    );
};

export default ProductDetailPage;

가령, 가상의 상품 상세 페이지가 있다고 할때. 이 컴포넌트는 3개의 하위 컴포넌트로 분리하여 관리할 수 있습니다.

const ProductDescription = ({ description }) => {
    return (
        <div>
            <h3>상품 설명</h3>
            <p>{description}</p>
        </div>
    );
};

export default ProductDescription;
const ProductPrice = ({ price, discount }) => {
    const finalPrice = discount ? price * (1 - discount) : price;

    return (
        <div>
            {discount && <span>원래 가격: {price}원</span>}
            <strong>최종 가격: {finalPrice}원</strong>
        </div>
    );
};

export default ProductPrice;
const QuantitySelector = ({ onQuantityChange }) => {

	(...)

    return (
        <div>
            <button onClick={handleDecrement}>-</button>
            <span>{quantity}</span>
            <button onClick={handleIncrement}>+</button>
        </div>
    );
};

export default QuantitySelector;

이렇게 되면, 각 컴포넌트는 자신의 책임에만 집중하며, 필요한 데이터는 속성(props)을 통해 전달받습니다. 이로써 각 컴포넌트의 재사용성과 유지보수성이 증가하며, 전체 페이지의 구조가 명확하고 관리하기 쉬워집니다.



4. 결론: 컴포넌트는 어떤 경우에 나누고, 또 어떻게 나누어야하는가.

React.js에서 컴포넌트를 나누는 것은 위에서 언급한 장단점을 숙지한 상태에서, 개발자의 판단과 프로젝트의 요구사항에 맞게 '알아서 잘 적절히' 이루어져야 합니다.

구현한 기능이 효율적으로 동작하는가, 코드의 유지보수가 원활한가, 요구사항의 변화로 애플리케이션을 확장할 필요성이 발생했을 때 신속하게 대처할 수 있는가 등등. 기본적인 원칙을 준수하면서 필요에 따라 적절한 수준에서 컴포넌트는 나누어져야 합니다.

profile
프론트엔드 개발자를 준비하고 있습니다.

0개의 댓글