Composition
여러 개의 컴포넌트를 합쳐서 새로운 컴포넌트를 만드는 것 ( 합성 )
Containment
여러개의 컴포넌트들을 어떻게 조합할 것인가?
- Contain : 담다, 포함하다
- 하위 컴포넌트를 포함하는 형태의 합성 방법
- Sidebar나 Dialog 같이 '범용적인' Box 역할을 하는 컴포넌트는 자신의 하위 컴포넌트를 미리 알 수 없다.
→ 이러한 경우, children이라는 prop을 사용해서 조합한다. ( 세부적 )
컴포넌트에서 다른 컴포넌트를 담기
어떤 컴포넌트들은 어떤 자식 엘리먼트가 들어올 지 미리 예상할 수 없는 경우가 있습니다. 범용적인 ‘박스’ 역할을 하는 Sidebar 혹은 Dialog와 같은 컴포넌트에서 특히 자주 볼 수 있습니다.
이러한 컴포넌트에서는 특수한 children prop을 사용하여 자식 엘리먼트를 출력에 그대로 전달하는 것이 좋습니다.
<리액트 공식문서>
📌 children prop을 사용한 FancyBorder 컴포넌트 ( Composition-Containment )
function FancyBorder(props) {
return (
<div className={'FancyBorder FancyBorder-' + props.color}>
{props.children} </div>
);
}
children prop은 개발자가 직접 넣어주는 것이 아니라, 리액트에서 기본적으로 제공해준다.
React.createElement(
type,
[props],
[...children]
);
function WelcomeDialog() {
return (
<FancyBorder color="blue">
<h1 className="Dialog-title">Welcome</h1>
<p className="Dialog-message">Thank you for visiting our spacecraft!</p>
</FancyBorder>
);
}
FancyBorder 컴포넌트 안에 있는 모든 JSX 태그는 children(props.children)으로 전달된다.
✅ <FancyBorder> JSX 태그 안에 있는 것들이 FancyBorder 컴포넌트의 children prop으로 전달된다.
여러개의 children 집합이 필요한 경우는 어떻게 할까?
아래 코드와 같이, 별도로 props을 정의해서 각각 원하는 컴포넌트에 넣어주면 된다.
function SplitPane(props) {
return (
<div className="SplitPane">
<div className="SplitPane-left">
{props.left} </div>
<div className="SplitPane-right">
{props.right} </div>
</div>
);
}
function App() {
return (
<SplitPane
left={
<Contacts /> }
right={
<Chat /> } />
);
}
✅ Containment : props.children이나 직접 정의한 props를 이용해 하위 컴포넌트를 포함하는 형태로 합성하는 방법
Specialization
- 전문화, 특수화
- WelcomeDialog(구체적)는 Dialog(범용적)의 특별한 케이스이다.
- 즉, 범용적인 개념을 구별이 되게 구체화 하는 것
- 기존의 객체지향 언어에서는 상속(Inheritance)을 사용하여 Specialization을 구현하지만
리액트에서는 합성(composition)을 사용하여 Specialiization을 구현한다.
📌 Dialog 컴포넌트를 WelcomeDialog로 구체화 ( 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() {
return (
<Dialog title="Welcome" message="Thank you for visiting our spacecraft!" /> );
}
✅ Specialization : 범용적으로 사용할 수 있는 컴포넌트를 만들어 놓고, 이를 특수화 시켜서 컴포넌트를 사용하는 방법
Containment와 Specialization을 같이 사용하기
📌 Containment(props.children) + 직접 정의한 props 사용(Specialization)
function Dialog(props) {
return (
<FancyBorder color="blue">
<h1 className="Dialog-title">
{props.title}
</h1>
<p className="Dialog-message">
{props.message}
</p>
{props.children}
</FancyBorder>
);
// <!-- Containment -->
}
class SignUpDialog extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.handleSignUp = this.handleSignUp.bind(this);
this.state = {login: ''};
}
render() {
return (
<Dialog title="Mars Exploration Program" message="How should we refer to you?">
<input value={this.state.login} onChange={this.handleChange} />
<button onClick={this.handleSignUp}> Sign Me Up! </button>
</Dialog>
);
}
// <!-- Specialization -->
handleChange(e) {
this.setState({login: e.target.value});
}
handleSignUp() {
alert(`Welcome aboard, ${this.state.login}!`);
}
}
input, button는 props.children이 쓰이고 있는 FancyBorder의 상위 컴포넌트(Dialog)에서 선언되며,
props.children을 통해 FancyBorder 컴포넌트에 전달된다.
<Dialog> JSX 태그 안에 있는 것들이 Dialog 컴포넌트의 children prop으로 전달된다.
Inheritance
Composition과 대비되는 개념이다. 객체지향 프로그래밍에서 상속은
- 부모 클래스를 상속받아 새로운 자식클래스를 만드는 개념으로
- 자식 클래스는 부모가 가진 변수나 함수 등의 속성들을 모두 갖게 된다.
반면 리액트에서는, 다른 컴포넌트로부터 상속을 받아서 새로운 컴포넌트를 만드는 것을 의미한다.
Summary
복잡한 컴포넌트를 쪼개서 여러개의 컴포넌트를 만들고, 만든 컴포넌트들을 조합해서 새로운 컴포넌트를 만들자!
🚀 참고
- 처음 만난 리액트(React) , 소플 - 섹션13. Composition vs Inheritance
- 리액트 공식문서 - 11. 합성 vs 상속
'React' 카테고리의 다른 글
[React] Context API - useContext() (0) | 2023.01.07 |
---|---|
[React] Context 개념 및 특징 (0) | 2023.01.06 |
[React] Hook의 규칙과 Custom Hook - 커스텀 훅 특징 및 사용법 (0) | 2022.12.30 |
[React] React Hook의 종류 - useMemo(), useCallback(), useRef() (0) | 2022.12.29 |
[React] React Hook의 개념과 종류 - useState(), useEffect() (0) | 2022.12.29 |
댓글