안녕하세요. 이번 시간에는 React 컴포넌트를 직접 만들어보겠습니다. ES2015 문법을 사용할 거니깐, 잘 모르시면 ES2015 강좌를 먼저 보고 오세요! ES2015는 꼭 익혀두어야 합니다. 2~3년 후에는 대부분 ES2015를 사용하고 있을 거니깐요. 특히 BabelJS를 보셔야 ES2015 코드를 자바스크립트로 변환할 수 있습니다.
기초적인 컴포넌트입니다.
basic.js
import React, { Component } from 'react';
export default class Basic extends Component {
renderSeparate() {
return (
<div>코드를 분리합시다</div>
);
}
render() {
return (
<div>
<span>저는 컴포넌트입니다!</span>
<span>독립 만세!</span>
<span>재사용 만세!</span>
{this.renderSeparate()}
</div>
);
}
}
react 모듈로부터 Component를 상속받는 Basic 클래스를 만들었습니다. Component를 상속받아야 이 코드가 리액트 컴포넌트임을 자바스크립트 엔진이 알 수 있습니다. Basic이 이 컴포넌트의 이름입니다. 마지막 render 메소드부터 봅시다. Component에는 render 메소드가 있는데 이 메소드가 반환하는 게 실제로 보여지는 DOM이 됩니다.
잠깐, 자바스크립트인데 html이 들어있죠? 문자열도 아니고 생 HTML입니다. 이상하죠? 저도 처음에 이 이상한 문법에 적응하느라고 힘들었습니다. JSX라고 불리는 문법입니다. 이 자바스크립트 파일 하나가 독립적인 컴포넌트 임무를 수행해야 하므로 자바스크립트 코드와 HTML 코드가 같이 있습니다. 사실 자바스크립트 코드로 완전히 HTML 코드를 대체할 수 있지만, 별로 추천하고 싶지는 않습니다. 가독성이 떨어지거든요.
JSX를 사용할 때는 몇 가지 알아두셔야 할 점이 있습니다. 컴포넌트는 반드시 하나의 노드로부터 시작해야 합니다. 위의 예시에서는 span 3개가 div로 감싸져 있습니다. 꼭 div일 필요는 없지만, 컴포넌트는 반드시 하나의 태그로 감싸져 있어야 합니다. 이게 단점이기도 합니다. React 16부터는 이 문제가 해결되었습니다. 아래와 같이 하면 됩니다. 대신 각각의 요소에 키를 주도록 합시다.
return [
<div key="a">A</div>,
<div key="b">B</div>
];
리액트 16.2부터 이렇게도 가능합니다. import React, { Component, Fragment } from 'react'
를 한 후,
return (
<Fragment>
<div>A</div>
<div>B</div>
</Fragment>
)
개인적으로는 배열보다는 Fragment를 쓰는 것이 깔끔해보입니다.
또, 속성 명으로 자바스크립트처럼 camelCase를 사용해야 하고요. 만약 img 같이 태그 안에 내용이 없는 경우 꼭 />로 닫아주어야 합니다. 그리고 class가 아니라 className을 사용하셔야 한다는 거 잊지 마세요! (class는 자바스크립트에서 예약어이기 때문에 className으로 대체되었습니다. 비슷한 예로, label의 for 속성은 htmlFor로 대신합니다.)
조건문을 안에 넣을 수도 있습니다. 대신 if문이 아니라 삼항 연산자를 사용해야 합니다. 아래의 예시에서는 condition을 만족하면 className이 imageHighlight가 되고, 아닌 경우에는 image가 됩니다. 또한 condition을 만족할 경우에만 button을 렌더링합니다. 종합해서 한 예시로 보여드리겠습니다. onClick이 camelCase인 것에 주의하세요!
return (
<div>
<img src="주소" className={condition ? 'imageHighlight' : 'image'} />
{condition && <button onClick={this.onClickButton}>클릭</button>}
</div>
);
다시 원래 코드로 돌아가서 보면, span 3개 밑에 renderSeparate 함수를 호출하는 부분이 있네요. 이제 renderSeparate 메소드를 보죠. renderSeparate함수는 똑같이 JSX를 return하지만 아래의 render 메소드에서처럼 실행을 시켜야만 render됩니다. 이렇게 코드를 분리해 특정한 조건에만 render한다든지 할 수 있습니다.
사실 위처럼 간단한 코드는 class를 사용하지 말고 간단한 함수로 만드는 게 낫습니다. 특히 render 메소드밖에 없는 경우 주로 이렇게 함수로 만듭니다.
const renderSeparate = () => <div>코드를 분리합시다</div>;
export default const Basic = () => {
return (
<div>
<span>저는 컴포넌트입니다!</span>
<span>독립 만세!</span>
<span>재사용 만세!</span>
{renderSeparate()}
</div>
);
};
class로 만들었든 함수로 만들었든 간에 만들어진 컴포넌트는
<Basic />
이렇게 부모 컴포넌트에서 사용할 수 있습니다. ES2015의 모듈 시스템을 사용하면 한 컴포넌트당 파일 하나를 만들어서 효율적으로 관리할 수도 있습니다! 컴포넌트가 export default 구문으로 export되는 게 보이시죠?
이렇게 만든 basic.js를 render.js에서 import하고 바벨로 render.js를 컴파일합니다.
render.js
import Basic from './basic';
import { render } from 'react-dom';
render(<Basic />, document.getElementById('root'));
render.js를 보면 root 아이디를 가진 태그에 Basic 컴포넌트를 넣는 것을 볼 수 있습니다. react.html을 만들어서 #root 태그와 바벨로 컴파일 된 render.js를 넣고 실행해봅시다.
react.html
<html>
<body>
<div id="root"></div>
<script src="./render.js"></script>
</body>
</html>
지금까지 JSX 문법과 간단한 컴포넌트에 대해서 알아봤는데요. 컴포넌트가 정적이라 재미가 없네요. 다음 강좌에서는 컴포넌트를 동적으로 만드는 props와 state에 대해 알아보겠습니다!
같은 폴더에 두고 실행시켯는데요..