합성 (Composition)

수경, Sugyeong·2022년 1월 23일
0

React

목록 보기
3/5
post-thumbnail

1. 합성 (Composition) 과 그것의 사용

리액트에는 컴포넌트 간에 코드를 재사용할 수 있게 해주는 합성 (Composition) 모델이라는 것이 존재한다. 작은 빌딩 블록(컴포넌트)을 모아서 사용자 인터페이스를 만드는 것이라고도 한다.

구체적으로는 컴포넌트의 공통된 UI 적인 요소, border-radius, box-shadow 등의 인터페이스를 만드는 박스나 쉘 역할을 하는 컴포넌트를 만들고 그것이 Wrapper 컴포넌트가 되어 자식 요소의 출력을 그대로 돕는다.

예시를 들어 설명해보자면 아래 이미지에서 (1)번 컴포넌트와 (2)번 컴포넌트에서 공통적으로 적용된 CSS 요소인 border-radius, box-shadow 를 따로 Card 라는 이름의 컴포넌트로 만들어서 분리하고 그것을 사용하고자 하는 컴포넌트 파일에 import 하여 사용하는 것이다.

웹 개발 영역에서 Card 용어를 사용한다면 그것은 상자처럼 보이는 것을 의미한다고 한다.

Card.js 컴포넌트

import './Card.css';

function Card(props) {
  return <div className="card"></div>;
}

export default Card;

Card.css

.card {
  border-radius: 12px;
  box-shadow: 0 1px 8px rgba(0, 0, 0, 0.25);
}

변경 전 (2) ExpenseItem.js 컴포넌트

import ExpenseDate from './ExpenseDate';
import Card from './Card';
import './ExpenseItem.css';

function ExpenseItem(props) {
  return (
    <div className="expense-item">
      <ExpenseDate date={props.date} />
      <div className="expense-item__description">
        <h2>{props.title}</h2>
        <div className="expense-item__price">${props.amount}</div>
      </div>
    </div>
  );
}

export default ExpenseItem;

변경 후 (2) ExpenseItem.js 컴포넌트

import ExpenseDate from './ExpenseDate';
import Card from './Card';
import './ExpenseItem.css';

function ExpenseItem(props) {
  return (
    <Card className="expense-item"> // <Card> 로 변경됨
      <ExpenseDate date={props.date} />
      <div className="expense-item__description">
        <h2>{props.title}</h2>
        <div className="expense-item__price">${props.amount}</div>
      </div>
    </Card> // </Card> 로 변경됨
  );
}

export default ExpenseItem;

위의 파일에서 <div> 가 아닌 <Card> 라는 Wrapper 컴포넌트로 감싸주게 되면 화면에 출력되는 모든 요소가 사라지게 된다. 그 이유는 Custom 컴포넌트인 Card.js 를 다른 컨텐츠에서 Wrapper 로 사용할 수 없기 때문이다. 또한 opening tag 와 closing tag 사이에 컨텐츠가 있으면 작동하지 않는다.

그렇다면 이를 해결할 방법이 아예 없는 것은 아니다! 리액트에는 방법이 있다.

바로 props.children 을 사용하는 것이다.


2. props.children

모든 컴포넌트가 받을 수 있는 특별한 props 가 리액트에 빌트인 되어 있는데 그것이 바로 props.children 이다. 다른 컴포넌트에서 opening tag 와 closing tag 사이에 컨텐츠를 모두 받는 방법이며 custom 컴포넌트 (Card.js) 를 다른 컴포넌트에서 Wrapper 로 사용할 수 있게 해준다.

Card.js 컴포넌트

Card.js 에서 {props.children} 을 작성해준다면 다른 컴포넌트에서 JSX를 중첩하여 임의의 자식을 전달할 수 있다.

또한 Card.js 의 className 을 const classes = 'card ' + props.className 으로 작성함으로써 공통적으로 적용하기 위해 따로 분리한 UI 적인 요소 뿐만 아니라 Wrapper 컴포넌트(ExpenseItem.js)의 className 도 함께 적용이 되어 화면에 출력된다.

ExpenseItem.js 컴포넌트

<Card> JSX 태그 안에 있는 것들이 Card 컴포넌트의 children prop으로 전달된다. Card{props.children}<div> 안에 렌더링하므로 전달된 엘리먼트들이 최종 출력된다.

이러한 작업을 통해 우리는 HTML 코드를 추출할 수도 있고 div에 있는 JSX 코드도 추출 할 수 있다. 코드를 추출 및 복제를 저장할 수 있게 되어 다른 컴포넌트는 깔끔하게 유지할 수 있다. 즉, Card 를 Wrapper 로 구성할 수 있고 빌트인 HTML 요소를 이용해서 구성할 수 있다.

모든 컴포넌트와 요소가 함께 모여서 전체적인 ExpenseItem 컴포넌트를 형성하며 사용자 인터페이스를 만든다.

결론적으로, 합성 (Composition) 에서 중요한 점은 props.children 이며 이것은 Wrapper 컴포넌트를 만들 수 있게 도와준다.


Udemy 강의
React 공식 문서

0개의 댓글