React in Action #2
2. First Component
컴포넌트를 구성하기 위한 계획을 세우려면 디자인 시안 외에 API가 애플리케이션에 어떤 데이터를 제공해 주는지 알아야 한다.
[Web API]: Application Programming Interface, 소프트웨어를 개발하기 위한 루틴과 프로토콜의 집합으로 프로그램이나 플랫폼과 상호작용을 하기 위해 정해진 것을 외부에 노출하는 방법
2.1.2 다중 컴포넌트: 컴포넌트의 조합과 부모-자식 관계
컴포넌트는 조합이 가능하기 때문에 애플리케이션의 여러 위치에서 재사용이 가능하다. 이때 컴포넌트는 위치와는 관계없이 부모-자식 관계를 형성한다. 즉, 컴포넌트가 다른 컴포넌트를 포함하고 있다면 이 컴포넌트는 부모 컴포넌트가 되며, 반대로 다른 컴포넌트 내에 포함된 컴포넌트는 자식 컴포넌트가 된다. 한편, 어떤 컴포넌트가 다른 컴포넌트와 같은 계층에 위치하는 경우에는 설령 두 컴포넌트가 인접해 있다 하더라도 직접적인 관계를 전혀 갖지 않는다. 컴포넌트에 있어서는 오로지 부모와 자식 관계만이 중요하다.
2.1.3 컴포넌트 간의 관계 확립
- 컴포넌트를 적절하게 그룹화하도록 한다. 컴포넌트를 애플리케이션 내에 자유롭게 배치하기 어렵다면 아마도 계층 구조를 너무 견고하게 정의했기 때문일 것이다.
- 인터페이스의 어떤 요소가 여러 번 반복되어 나타난다면 이런 요소들은 컴포트로 정의하면 좋다.
- 처음부터 완벽한 구조를 갖추는 것 보다는 계속 반복해서 코드를 개선하는 것이 일반적이다.
2.2 Develope Component
[기본 코드]
// ... index.js
const node = document.getElmentById("root"); (1)
// 이제부터 개발할 리액트 앱은 이 DOM 요소 내에 렌더링 된다.
// ... index.html
<div id="root"></div>
// index.html 파일에는 id 속성 값이 'root'인 div 요소를 생성한다.
2.2.1 리액트 요소 생성하기
[ReactDOM.render 메서드의 시그너처]
ReactDOM.render(
ReactElement element,
DOMElement container,
[function callback]
) -> eactComponent
React DOM은 ReactElement 타입의 요소와 DOM 요소를 필요로 한다.
리액트 요소란 경량이고 상태가 없으며 내부 상태의 변경이 불가능한 요소를 말한다. 리액트 요소에는 크게 ReactComponentElement 타입과 ReactDOMElement 타입의 두 가지가 존재하는데 ReactComponentElement는 DOM 요소를 가상으로 표현한 객체이며, 반면 ReactComponentElement는 리액트 컴포넌트를 표현하는 함수나 클래스에 대한 참조를 의미한다.
[React.createElement 함수의 사용 예]
import React, { component } from 'react';
import {render } "react-dom";
const node = document.getElementById('root');
const root = React.createElement('div', {},
React.createElement('h1', {}, "Hello, world!",
React.createElement('a', {href: 'mailto:mark@ifelse.io'},
React.createElement('h1', {}, "React In Action"),
React.createElement('em', {}, "... and not it really is!")
)
)
);
render(root, node);
2.2.4 리액트 클래스 생성하기
class MyReactClassComponent extends Component {
render() {}
}
리액트 라이브러리가 제공하는 React.createElement 같은 특정한 함수를 호출하는 방법 대신 React.Componenet 클래스를 기반으로 컴포넌트를 생성하기 위해서는 React.Component 추상 기반 클래스를 상속하는 자바스크립트 클래스를 선언하면 된다. 이 기반 클래스를 상속하는 클래스는 대부분 하나의 리액트 요소 또는 리액트 요소의 배열을 리턴하는 render 메서드를 정의한다.
‘리액트 클래스를 이용해서 컴포넌트를 생성하면 props 객체에 접근할 수 있다.’
2.2.6 PropTypes를 이용한 속성의 유효성 검사
리액트 클래스 컴포넌트는 자유롭게 속성을 정의할 수 있다는 점에서 매력적이지만, 사용하고자 하는 속성에 대한 유효성 검사를 수행할 방법을 제공해서 버그를 예방하고 컴포넌트가 사용할 데이터의 종류에 대한 계획을 세워야한다. 유효성 검사는 React 네임스페이스 내에 정의된 유효성 검사 도구(validators)인 ProTypes 패키지를 설치하여 이용하면 된다.
prop-types 라이브러리는 컴포넌트가 필요로 하는, 혹은 사용할 것으로 예상하는 속성들을 지정할 수 있는 유효성 검사 도구들을 제공한다. 컴포넌트가 동작하기 위해 필요한 속성은 무엇이며, 어떤 데이터를 전달해야 하는지를 지정할 수 있으며 반드시 필요한 것은 아니지만 버그의 예방과 손쉬운 디버깅을 위해 가급적 활용하는 편이 좋다.
[중첩된 컴포넌트 추가하기]
import React, { Component } from "react";
import { render } from "react-dom";
import PropTypes from "prop-types";
const node = document.getElementById("root");
class Post extends Component {
render() {
return React.createElement(
"div",
{
className: "post"
},
React.createElement(
"h2",
{
className: "postAuthor",
id: this.props.id
},
this.props.user,
React.createElement(
"span",
{
className: "postBody"
},
this.props.content
),
this.props.children
)
);
}
}
Post.propTypes = {
user: PropTypes.string.isRequired,
content: PropTypes.string.isRequired,
id: PropTypes.number.isRequired
};
class Comment extends Component {
render() {
console.log("yo");
return React.createElement(
"div",
{
className: "comment"
},
React.createElement(
"h2",
{
className: "commentAuthor"
},
this.props.user,
React.createElement(
"span",
{
className: "commentContent"
},
this.props.content
)
)
);
}
}
Comment.propTypes = {
id: PropTypes.number.isRequired,
content: PropTypes.string.isRequired,
user: PropTypes.string.isRequired
};
const App = React.createElement(
Post,
{
id: 1,
content: " said: This is a post!",
user: "mark"
},
React.createElement(Comment, {
id: 2,
user: "bob",
content: " commented: wow! how cool!"
})
);
render(App, node);