🗂 목차
Components and Props
컴포넌트는 UI를 독립적이고 재사용이 가능한 조각, 각각 독립된 부분으로 생각하게 해줍니다. 이 페이지에서는 컴포넌트의 대한 개념을 소개합니다.
개념적으로 컴포넌트는 JS의 함수와 비슷합니다. Props 라는 임의의 값을 받아서 화면에 명시할 React Element 를 리턴합니다.
Function and Class Components
컴포넌트를 정의 하는 가장 쉬운 방법은 JS의 함수로 작성하는 방식입니다.
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
이 함수는 props 라는 객체를 인자로 받아서 React Element 를 리턴하는 컴포넌트 입니다. JS의 함수로 작성 되었기 때문에 말 그대로 “Function Component (함수형 컴포넌트)” 라고 부릅니다.
ES6 class로도 컴포넌트를 정의 할 수 있습니다. (클래스형 컴포넌트)
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
위 두 컴포넌트는 React의 관점으로 봤을 때 동등한 가치를 지닙니다.
Rendering a Component
이전까지는 element를 DOM 태그 로만 나타냈습니다.
const element = <div />;
하지만 사용자 정의 컴포넌트 또한 element로 정의 할 수 있습니다.
const element = <Welcome name="Sara" />;
React가 사용자 정의 컴포넌트를 발견하면 JSX의 속성과 자식을 해당 컴포넌트에 단일 객체로 전달합니다. 그것을 “Props” 라고 부릅니다.
아래는 “Hello, Sara” 를 화면에 렌더링을 하는 예제 입니다.
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
const element = <Welcome name="Sara" />;
ReactDOM.render(
element,
document.getElementById('root')
);
위 코드가 동작하는 순서입니다.
<Welcome name=”Sara” />
로ReactDOM.render()
를 호출 합니다.- React는
{ name: ‘Sara’ }
를 props로Welcome
컴포넌트를 호출합니다. Welcome
컴포넌트는<h1>Hello, Sara</h1>
element 를 리턴합니다.- React DOM 은 효율적으로
<h1>Hello, Sara</h1>
element 와 일치하도록 DOM을 업데이트 합니다.
경고: 컴포넌트의 이름은 항상 대문자로 시작해야 합니다.
React는 소문자로 시작하는 컴포넌트를 DOM 태그로 인지합니다. 예로<div />
는 HTML div 태그 입니다. 하지만<Welcome />
은 컴포넌트입니다.Welcome
컴포넌트는 안에Welcome
을 포함해야합니다.
Composing Components
컴포넌트는 다른 컴포넌트를 참조해서 출력할 수 있습니다. 모든 세부 단계에서 동일한 추상 컴포넌트를 사용할 수 있습니다. 흔히 React 앱 에서는 버튼, 폼, 다이얼로그, 화면 등의 모든 것들이 컴포넌트로 표현됩니다.
예시로 Welcome
컴포넌트를 여러번 호출하는 App 컴포넌트를 작성할 수 있습니다:
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
function App() {
return (
<div>
<Welcome name="Sara" />
<Welcome name="Cahal" />
<Welcome name="Edite" />
</div>
);
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
일반적으로 새 React 앱은 최상위 컴포넌트로 APP
컴포넌트를 가집니다. 하지만 기존 앱에 React를 통합하는 경우에는 Button
과 같은 작은 컴포넌트부터 시작해서 뷰 계층의 상단으로 올라가면서 작업해야 할 수 있습니다.
Extracting Components
컴포넌트를 여러개의 작은 컴포넌트로 나누는 것을 두려워하지 마세요.
Comment
컴포넌트를 봅시다.
function Comment(props) {
return (
<div className="Comment">
<div className="UserInfo">
<img className="Avatar"
src={props.author.avatarUrl}
alt={props.author.name}
/>
<div className="UserInfo-name">
{props.author.name}
</div>
</div>
<div className="Comment-text">
{props.text}
</div>
<div className="Comment-date">
{formatDate(props.date)}
</div>
</div>
);
}
이것은 props로 author
(객체), text
(문자열), date
(날짜) 를 받아서 소셜 미디어의 댓글을 나타냅니다.
이 컴포넌트는 구성요소들이 모두 중첩 구조로 이루어져 있어서 변경하기 어려울 수 있으며, 각 구성요소를 개별적으로 재사용 하기도 힘듭니다. 이 컴포넌트에서 몇 가지 컴포넌트를 추출하겠습니다.
첫 번째로 Avatar
를 추출하겠습니다.
function Avatar(props) {
return (
<img className="Avatar"
src={props.user.avatarUrl}
alt={props.user.name}
/>
);
}
Avatar
는 자신이 Comment
안에서 렌더링 된다는 것을 알 필요가 없습니다. 이것은 props 이름이 일반화 되어야하는 이유 입니다. 따라서 props의 이름을 author
에서 더욱 일반화된 user
로 변경하였습니다.
props의 이름은 사용될 맥락, 부분이 아닌 컴포넌트 자체의 관점에서 짓는 것을 권장합니다.
이제 Comment
가 살짝 단순해졌습니다.
function Comment(props) {
return (
<div className="Comment">
<div className="UserInfo">
<Avatar user={props.author} />
<div className="UserInfo-name">
{props.author.name}
</div>
</div>
<div className="Comment-text">
{props.text}
</div>
<div className="Comment-date">
{formatDate(props.date)}
</div>
</div>
);
}
다음, Avatar
와 유저의 이름을 렌더링 하는 UserInfo
컴포넌트를 추출하겠습니다.
function UserInfo(props) {
return (
<div className="UserInfo">
<Avatar user={props.user} />
<div className="UserInfo-name">
{props.user.name}
</div>
</div>
);
}
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>
);
}
컴포넌트 추출은 지루해 보일 수 있습니다. 하지만 재사용 가능한 컴포넌트를 만드는 것은 큰 앱에서 비용을 줄일 수 있습니다. 만약 당신의 UI가 여러번 사용 되거나 ( Button
, Panel
, Avatar
), 하나의 컴포넌트가 복잡한 경우 ( App
, FeedStory
, Comment
) 재사용 가능한 컴포넌트가 될 만한 후보 입니다.
Props are Read-Only
함수 컴포넌트나 클래스 컴포넌트 모두 직접 컴포넌트의 props를 수정하면 안 됩니다. 다음 sum
함수를 봅시다.
function sum(a, b) {
return a + b;
}
입력 값을 바꾸려하지 않고, 같은 입력 값에 따라 항상 같은 값을 리턴하기 때문에 이러한 함수를 순수 함수 라고 부릅니다.
반대로 이 함수는 입력값을 바꾸기 때문에 순수 함수가 아닙니다.
function withdraw(account, amount) {
account.total -= amount;
}
React는 매우 유연하지만 한 가지 엄격한 규칙이 있습니다.
모든 React 컴포넌트는 자신의 props를 다룰 때 반드시 “순수 함수” 처럼 동작해야 합니다.
물론 애플리케이션 UI는 동적이며 시간에 따라 변합니다. 다음 장에서는 “state”라는 새로운 개념을 소개합니다. React 컴포넌트는 state를 통해 위 규칙을 위반하지 않고 사용자의 동작, 네트워크 응답 및 다른 요소에 대한 응답으로 시간에 따라 자신의 출력 값을 변경할 수 있습니다.
📚 정리 및 참고 자료
- 컴포넌트는 재사용성이 중요합니다.
- 컴포넌트의 이름은 대문자로 시작합니다.
- 컴포넌트가 props를 다룰 때는 순수 함수처럼 동작해야 합니다. (컴포넌트에서 직접 props를 수정할 수 없습니다.)
- props의 이름은 컴포넌트의 관점에서 짓는 것을 권장합니다.