이 장에서는 React의 문법과 JSX의 문법에 대해서 알아보도록 하겠습니다.
1. React의 문법
앞의 글에서 보았던 hello world 예제를 다시 보도록 하겠습니다.
[App.js]
import React, { Component } from 'react';
class App extends Component {
render() {
return (
<h1>
Hello,world!
</h1>
);
}
}
export default App;
위 예제에서 사용한 몇 가지 키워드에 대해 살펴보도록 하겠습니다.
(1) import, export
모듈을 불러올 때는 import를 사용하여야 하고, 모듈을 다른 파일로 보내려면(다른 모듈에서 import 하여 사용하도록 하게 하려면) export라고 명시해주어야 합니다. 위 예제에서는 default exports가 사용되었는데, default export는 모듈당 딱 하나만 존재합니다. 함수 또는 클래스, 객체 등 어떤 것이든 될 수 있고, 단일 값을 내보내거나 모듈에 대한 대체 값을 원할 때도 사용할 수 있습니다. import를 위해 내보낼 대표 값이므로 가장 메인에 해당하는 값으로 고려해야 합니다.
모듈 임포트에 구조분해 할당(destructuring assignment)을 적용하면, 모듈 내부 함수와 클래스에 직접 접근할 수 있습니다. import를 할 때 React 내부의 Component라는 모듈을 {} 안에 기재하는 것을 말하며, 이렇게 사용하였을 때 React.Component라고 기재하지 않고 Component라고 간단하게 표기가 가능합니다.
es6의 export
export에는 두 가지 다른 타입이 존재하는데 Named exports와 Default exports가 그것입니다. 자세한 내용은 여기에서 확인해 보시기 바랍니다.
(3) Component
React.Component를 확장(extends)해서 컴포넌트를 만든 것으로, 이에 대한 자세한 내용은 4. 컴포넌트에서 다루도록 하겠습니다. 지금은 이 모듈이 컴포넌트임을 나타낸다는 것만 알아두면 될 것입니다.
(4) render
컴포넌트를 생성하면 기본적으로 존재해야 하는 함수이며, 컴포넌트의 UI에 대한 설명을 반환하는 기능을 합니다. HTML DOM을 렌더링하여 사용자에게 보여주는 역할을 하는 것입니다. 여기에서 HTML DOM은 가상 DOM을 의미합니다. 컴포넌트가 마운트 될 때나 state에 변화가 일어나 DOM의 리렌더링이 필요할 때 호출되게 됩니다. state는 컴포넌트의 속성 중 하나로, 컴포넌트와 마찬가지로 4. 컴포넌트에서 자세히 다루도록 하겠습니다.
이어 또 다른 예제 index.js를 살펴보겠습니다.
[index.js]
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
ReactDOM.render(<App />, document.getElementById('root'));
여기에서 살펴 볼 것은 ReactDOM입니다. ES6를 기반으로 코드를 작성하고 있기 때문에 간단하게 import 하여 사용할 수 있지만, ES5에서는 var ReactDOM = require('react-dom'); 과 같이 객체로 생성해야 합니다.
차이를 조금 설명하자면, react는 UI라이브러리이며, react-dom 패키지는 이 UI라이브러리를 출력하는 역할을 수행합니다. 그러므로 DOM에 관련한 메서드를 제공합니다.
ReactDOM.reader() 메서드는 render 함수에 기재된 내용을 출력하는 역할을 합니다. 위 예제로 설명하자면, <App />는 App.js에서 작성한 App 컴포넌트를 가리키며, id가 root인 DOM 객체에 이 컴포넌트를 출력하는 동작을 수행하게 됩니다. 이는 ReactDOM.render() 메서드가 App 컴포넌트 내의 render() 메서드를 호출하며 recursive 하게 자식 컴포넌트들 전부의 render()를 호출하므로, 전체 컴포넌트가 동작하게 되는 것입니다.
React.render()? ReactDOM.render()?
간혹 React.render를 이용하는 코드를 보실 수 있을 텐데, 이는 이전 버전에서 사용되던 코드로 현재는 depricate되었습니다. React 0.14 버전이 도입되면서 React는 core 라이브러리와 DOM adapter로 나누어졌습니다. 이 과정에서 react는 UI를 위한 라이브러리로, react-dom 패키지는 UI라이브러리를 출력하기 위한 라이브러리로 나뉘어, 렌더링에 대한 역할이 react-dom의 역할이 되었습니다. 이로 인해 환경을 구성하는 것이 더 쉽고 명백해졌습니다.
2. JSX
JSX는 Javascript와 XML을 합쳐서 탄생한 용어로, 기존 자바스크립트의 확장 문법입니다.
React는 JSX 문법을 사용하여 UI를 구성하는데, 이 JSX를 사용하면 자바스크립트 코드에서 HTML형식을 그대로 사용할 수 있습니다.
JSX 문법을 사용하여 작성된 코드는 앞에서 언급했듯, 바벨의 JSX 로더를 통해 네이티브 자바스크립트로 변경됩니다. 아래와 같이 hello world라는 h1 태그는 트랜스파일을 거쳐 리액트 라이브러리에 대한 함수 호출로 변환됩니다.
-----JSX-----
<h1>Hello World</h1>
-----함수 호출로 변환-----
React.createElement("h1",null,"Hello World");
참고. createElement의 인자는 type, props, children을 의미합니다.
HTML과 유사하지만 지켜야할 규칙이 몇 가지 있습니다. 이는 HTML과의 차이점임과 동시에 특이점이기도 합니다.
(1) 낙타표기법(CamelCase : 각 단어의 첫 문자를 대문자로 표기하여 붙여 쓰되, 맨 처음 문자는 소문자로 표기)을 사용합니다.
-----HTML-----
<input type="text" maxlength="30" />
-----JSX-----
return <input type="text" maxLength="30" />
(2) 태그는 반드시 닫혀야 합니다.
<input type="text" />
태그가 닫히지 않으면 Failed to compile 에러가 발생하여 페이지가 로드되지 않습니다.
(3) 단일 루트 노드
리액트 컴포넌트는 단일 루트 노드만 렌더링할 수 있습니다. 즉 두 개 이상의 엘리먼트는 반드시 하나의 엘리먼트로 감싸져 있어야 합니다. 아래와 같이 작성할 경우 오류가 발생합니다.
return(
<div>내부 엘리먼트1<div>
<div>내부 엘리먼트2</div>
)
사실 이 특성은 JSX의 제한이 아니라 자바스크립트의 특징입니다. return문은 단일 값만 반환할 수 있지만, 위 코드는 두 개의 문을 반환하려고 합니다.(React.createElement를 두 번 호출) 그러므로 모든 반환 값을 루트 객체 하나에 래핑 하면 됩니다.
<div>
외부엘리먼트
<div>내부 엘리먼트1<div>
<div>내부 엘리먼트2</div>
</div>
위와 같이 작성하는 경우 정상 동작합니다.
이 경우 내부 엘리먼트를 감싸주는 추가적인 div가 하나 더 만들어지는데, 만약 이를 원하지 않는다면 v16.2에서 도입된 Fragment를 사용할 수 있습니다.
import React, { Component, Fragment } from 'react';
...
<Fragment>
외부엘리먼트
<div>내부 엘리먼트1<div>
<div>내부 엘리먼트2</div>
</Fragment>
React에 속한 속성이므로 import해주어야 사용 가능합니다.
(4) Javascript 동적 값 할당은 {}
자바스크립트의 객체를 JSX내에서 사용할 때에는 {}를 사용합니다.
...
render(){
const text = "var text";
return (
<h1>const scope : {text} </h1>
);
}
뿐만 아니라 함수 호출 역시 가능합니다.
...
<h1>block scope : {scopeTest(false)}</h1>
...
function scopeTest(flag){
let result;
const text = "outer";
if(flag){
const text = "inner";
result = text;
return result;
}
result = text;
return result;
}
여기에서 조금 낯선 let과 const가 보입니다. 이는 ES6에서 도입된 키워드로 var와 유사하다고 생각하시면 됩니다. 차이점은 const는 한번 선언한 뒤 바뀌지 않는 값을 의미하며, let은 바뀔 수 있는 값을 의미합니다. 이 두 키워드가 var와 다른 점은 함수 단위 scope인 var에 반해 let과 const는 block scope라는 것입니다. ES6에서는 var를 쓸 일이 없고 거의 let과 const를 사용하니, 자세한 내용은 링크에서 확인해 보시기 바랍니다.
(5) 조건부 렌더링
JSX 내부에서 조건부 렌더링을 할 때에는 삼항 연산자 또는 AND 연산자를 사용하며 if문을 사용할 수는 없습니다. 사용하고자 한다면 IIFE(즉시 실행 함수)를 사용해야 합니다.
삼항 연산자를 사용하면 아래와 같습니다.
<div>
{
1+1 === 2
? (<div>딩동댕</div>)
: (<div>땡</div>)
}
</div>
참고. div를 감싼 ()는 사용하지 않아도 상관없습니다. 식의 구분을 보여드리기 위해 추가한 것일 뿐입니다.
아래는 AND 연산자를 사용한 경우입니다.
<div>
{
1 + 1 === 2 && (<div>맞아요!</div>)
}
</div>
대부분 위와 같이 해결할 수 있으나 더 복잡한 코드를 짜야할 때가 있습니다. 그러한 경우에 JSX 밖에서 로직을 작성하는 게 좋지만 꼭 JSX 내에서 작성하여야 한다면 IIFE를 사용합니다.
<div>
{
(function() {
if (value === 1) return (<div>하나</div>);
if (value === 2) return (<div>둘</div>);
if (value === 3) return (<div>셋</div>);
})()
}
</div>
위 코드는 스위치 문으로 작성해도 무방합니다. 또한 이 코드는 화살표 함수로도 표현할 수 있습니다.
<div>
{
(() => {
if (value === 1) return (<div>하나</div>);
if (value === 2) return (<div>둘</div>);
if (value === 3) return (<div>셋</div>);
})()
}
</div>
화살표 함수는 this, arguments, super 개념이 없는 익명 함수이며 ES6에서 많이 사용하므로 링크를 통해 더욱 자세히 알아보셔도 좋을 것 같습니다. (화살표 함수에 관련한 내용은 화살표 함수 표현식 (arrow function expression)에서도 확인하실 수 있습니다.
(6) 공백 출력은 {" "} 또는
HTML의 경우 브라우저가 일반적으로 여러 행 요소 간에 공백을 출력합니다. 반면 JSX는 분명한 지시가 있을 때만 공백을 출력합니다.
return(
<a href="http://google.com">Google</a>
<a href="http://facebook.com">Facebook></a>
)
위 코드는 GoogleFacebook 으로 출력됩니다. 따라서 JSX에서 두 문자열 간에 공백을 넣어주고 싶다면 원하는 위치에 {" "}를 추가해 주어야 합니다. 역시 동일하게 동작합니다.
(7) 주석
HTML에서의 주석이 <!-- ... -->를 사용하는 것과 달리 JSX는 자바스크립트와 동일하게 // 와 /* ... */ 을 사용합니다. 단, 태그의 자식 섹션 안에 주석을 넣을 때는 중괄호({})로 주석을 감싸야합니다.
(8) style과 className
JSX에서 인라인 스타일과 클래스 이름을 지정하는 방식은 기존의 HTML과 약간 차이가 있습니다.
JSX에서는 객체 형태로 인라인 스타일을 작성해주어야 합니다. 인라인 스타일을 작성하는 법은 아래와 같습니다.
...
const style = {
backgroundColor: 'black',
padding: '16px',
color: 'white',
fontSize: '36px'
};
...
<div style={style}>안녕하세요!</div>;
다음으로 클래스를 지정하고자 할 때에는 className을 사용해주어야 합니다. (HTML에서 class와 동일한 동작을 수행합니다) 아래 예제에서는 CSS 스타일을 주어보도록 하겠습니다.
import './App.css'
...
<div className="App">
리액트
</div>
사용할 css파일을 반드시 import 해주어야 합니다. css파일에 들어갈 내용은 아래와 같습니다.
.App {
background: black;
color: aqua;
font-size: 36px;
padding: 1rem;
font-weight: 600;
}
여기까지 JSX문법을 사용할 때 주의해야 할 점을 알아보았습니다. JSX내에서 사용할 수 있는 것과 사용하면 안 되는 것, 이름이 다른 것들을 유의한다면 사용한다면 JSX 자체에 익숙해지는 것은 어렵지 않을 것입니다.
참고. React Developer Tools
Vue나 Angular가 그러하듯 React도 개발자를 위한 확장 프로그램을 제공합니다. Chrome 웹 스토어에서 React Developer Tools를 검색하여 설치하게 되면 브라우저 우측 상단에 아래와 같이 표시되는 것을 볼 수 있습니다. (Firefox 역시 확장 프로그램으로 제공하며, 사파리나 IE, React Native를 포함한 다른 환경에서는 standalone app으로 제공합니다)
React Developer Tools는 React의 컴포넌트 구조를 계층적으로 보여주며, 컴포넌트의 props와 state 역시 포함하여 보여줍니다.
(출처 : https://github.com/facebook/react-devtools)
위 사진처럼 React가 활성화되어 있는 화면의 경우, 개발자 도구(F12)에서 React 가 위치하고 있는 것을 볼 수 있습니다.
React의 컴포넌트 구조가 계층적으로 잘 나타나 있고, 해당하는 컴포넌트의 props와 state 역시 화면 오른쪽에 나타나는 것을 볼 수 있습니다.
자세한 내용은 https://github.com/facebook/react-devtools 에서 확인해 보실 수 있습니다.
Next..
다음 글에서는 컴포넌트와 props, state에 대해 다루고, 컴포넌트의 라이프사이클에 대해 알아보겠습니다.
[references]
'Front-end Framework > React (Reactjs)' 카테고리의 다른 글
6. React의 이벤트 처리 (0) | 2020.10.19 |
---|---|
5. 컴포넌트 라이프사이클 이벤트 (0) | 2020.10.19 |
4. 컴포넌트 (0) | 2020.10.19 |
2. React 개발 설정 (0) | 2020.10.19 |
1. React? (0) | 2020.10.19 |
댓글