(React 공식문서의 main concepts 번역 글입니다.)
함께보면 이해가 쏙쏙
https://youtu.be/T6Wj2pbkorA
composition
과 inheritance
는
component를 만드는 2가지 다른 패턴이다.
(https://www.youtube.com/watch?time_continue=238&v=wfMtDGfHWpA)
(위 영상을 참고하면 둘의 차이를 쉽게 이해할 수 있다.)
보충 설명을 하자면
composition
은 component가 무엇을 하는지를 기준으로 선언한다.
반면 inheritance
는 component가 무엇인지를 기준으로 선언한다.
React에서 inheritance
를 활용하면 코드 재사용성이 낮다.
반면에, composition
model은 재사용성이 높다.
inheritance
로는 재사용할 수 없는 상황이 있기 때문이다.
바로 그 한계상황에 대해, 아래에서 살펴볼 것이다.
또한 composition
으로 그 한계상황을 어떻게 극복할 수 있는지
그 해결방법도 함께 살펴 볼 것이다.
첫번째 한계상황인 containment이다.
어떤 component가 children 값을 미리 알 수 없는 경우가 있다.
보통 Sidebar
나 Dialog
가 이에 해당한다.
(일반적으로 박스 형태의 component가 이에 속한다.)
그런 경우에는 해당 component가 return하는 react element안에
직접 {children props}
를 넣어주는 것이 좋다.
그 결과, 어떠한 children props를 받더라도 render가 가능해진다.
function FancyBorder(props) {
return (
<div className={'FancyBorder FancyBorder-' + props.color}>
{props.children} </div>
);
}
위 코드와 같이 return하는 element에
직접 {children props}
를 넣으면
아래처럼 해당 component에게 다른 component가
tag 모음의 children을 props로 전달하더라도 render가 가능하다.
function WelcomeDialog() {
return (
<FancyBorder color="blue">
<h1 className="Dialog-title"> Welcome </h1> <p className="Dialog-message"> Thank you for visiting our spacecraft! </p> </FancyBorder>
);
}
위에서 하이라이팅된 부분, 즉 tag 모음 뿐만아니라
어떠한 것도 <FancyBorder>
JSX tag 로 감싸기만 하면
<FancyBorder>
는 children props로 전달받을 수 있다.
<FancyBorder>
는 <div>
로 감싸진 {props.children}
을 return하므로
children props로 전달 받은 어떠한 것이든 render할 수 있다.
특수한 경우에, 여러개의 {props.children}
가 필요할 수도 있다.
그러한 경우에는 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() {
return (
<SplitPane
left={
<Contacts /> }
right={
<Chat /> } />
);
}
<Contacts />
나 <Chat />
같은 react element는 객체이다.
따라서 react element들은 다른 data처럼 props로 전달할 수 있다.
두번째 한계상황은 특별한 component가 필요한 경우이다.
이 경우, 일반적인 component를 수정하여 특별한 component를 만든다.
예를 들어 <Dialog>
는 일반적인 component이다.
이를 수정하면 특별한 component인 <WelcomeDialog>
를 만들 수 있다.
React에서 특별한 component는 composition으로 만들 수 있다.
즉 일반적인 component에게 props를 주어 특별한 component로 만든다.
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!" />
);
}
일반적인 component인 <Dialog>
에
title과 message props를 주어
특별한 component인 <WelcomeDialog>
를 만들었다.
function component 뿐아니라 class component에서도
composition으로 동일하게 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>
);
}
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>
);
}
handleChange(e) {
this.setState({login: e.target.value});
}
handleSignUp() {
alert(`Welcome aboard, ${this.state.login}!`);
}
}
페이스북에서는 composition
을 활용하여 component를 만든다.
왜냐하면 inheritance
보다 효율이 좋기 때문이다.
props와 composition을 활용하면 일반적인 component를
명백하고 안전하게, 특별한 component로 만들 수 있게 된다.
그 component는 임의의 props(primitive value, function,
심지어 react element까지)를 받아들일 수 있기 때문이다.
만약 UI로직과 관련이 없는 function을 재사용 하기 원한다면
해당 function을 extract하는 것을 추천한다.
특정 component가 해당 function이 필요하면 import해서 쓸 수 있다.
inheritance
를 통해 function 코드를 재사용하는 대신에!