최근들어서 Angular, Vue.js, React.js는 삼대장으로 불리며 가장 많이 각광받고 있는 프론트엔드 언어입니다.
그 중에 리액트는 페이스북에서 제공해주는 프론트엔드 라이브러리입니다.
위의 프레임워크들은 MVC 패턴 또는 MVVM등의 패턴으로 애플리케이션을 구조화하고 있습니다.
즉, 이벤트가 발생했을 때 모델(Model)에서 데이터를 처리하여 그 정보를 바탕으로 화면을 담당하는 뷰(View)를 변화시켜줍니다. 이 과정은 간단해 보이지만, 애플리케이션 규모가 크면 상당히 복잡하고 성능도 떨어집니다. 여기서 페이스북 개발팀이 생각한 아이디어는, 데이터가 변할 때마다 어떤 변화를 줄지를 고민하는 것이 아니라 기존 뷰를 날려 버리고 Virtual DOM을 사용하여 처음부터 새로 렌더링
하는 방식으로 좀 더 빠른 속도로 뷰(View)를 변경시켜주게 됩니다.
리액트는 모든 것이 컴포넌트입니다. 컴포넌트는 레고 블록과 같이 작은 단위로 만들어서 그것들을 조립하듯이 개발할 수 있게 해주기 떄문에 캡슐화, 확장성, 결합성, 재사용성 등과 같은 이점이 있습니다.
React에서 부모 컴포넌트와 자식 컴포넌트간에 데이터를 전달할 수 있는데, 데이터를 전달할 때 부모에서 자식에게로만 데이터가 전달이 가능합니다.
리액트 개발에서는 ES6 문법을 사용하고 있습니다.
- let
기존의 var를 대체 할 수 있는 키워드입니다. 기존의 var는 선언문의 생략, 중복된 변수명 선언, 함수 블록에서의 스코프 설정, 함수 호이스팅 등으로 개발에 혼란을 주고 가독성이 떨어지기 때문에 ES6에서 var를 지양하고 있습니다.
함수가 아닌 블록에서의 var 스코프 설정
var a = 100;
if(a > 0){
var a = 200;
console.log(a); // 200출력
}
console.log(a); // 200 출력
위 예시를 let으로 변경했을 경우 ⇒ 함수 이외의 블록에서도 스코프 설정이 가능해집니다.
let a = 100;
if(a > 0){
let a = 200;
console.log(a); // 200출력
}
console.log(a); // 100 출력
- const
변경할 수 없는 변수로, 값을 재할당 할 필요가 없는 경우 사용합니다. 변수와 달리 선언 시에 반드시 초기값을 할당해줘야 하며, 스코프 범위는 let과 동일하게 블록 레벨입니다.
- 화살표 함수
함수표기 구문을 화살표 => 로 하여 구문을 짧게 줄여줍니다.
// 기존 함수 구문
var add = function(a, b){
return a + b;
};
// 화살표 함수 구문
let add = (a, b) => {
return a + b;
}
블록 구문 {}을 생략한 표현식 사용은 가능 하지만 이 경우 return은 사용 불가능합니다.
// 블록 구문 사용
let add = (a, b) => {
console.log(a + b);
}
// 블록 구문 생략
let add = (a, b) => console.log(a + b);
단일 인자만 넘겨받는 경우 {}괄호 생략도 가능합니다.
// 괄호 사용
let print = (message) => document.write(message);
// 괄호 생략
let print = message => document.write(message);
- 펼침 연산자(spread operator)
... 을 사용하는 연산자로 배열 또는 객체의 모든 값을 복사할 수 있습니다.
let a = [1,2,3]
let b = a
b.push(4);
console.log(a)//[1,2,3,4]
console.log(b)//[1,2,3,4]
위 예시처럼 배열의 모든 데이터가 교체되는 일을 방지하기 위해 나온 문법이 펼침 연산자로, 데이터 불변성과 관련있습니다.
let a = [1,2,3]
let b = [...a, 4]
console.log(a) //[1,2,3]
console.log(b) //[1,2,3,4]
- 클래스
class를 사용하여 Prototype을 사용하지 않고도 간단하게 상속을 사용할 수 있게 되었습니다.
// class키워드 뒤에 클래스명 붙여 선언하고 블록 안쪽에 구문 작성
class Display {
}
const display = new Display();
- 상속
ES6에서는 extends키워드를 사용하여 보다 쉽게 상속을 구현할 수 있는데, 말 그대로 부모(상위) 클래스의 속성이나 기능을 자식에게 전달한다는 의미입니다.
class Display{
constructor(x, y){
this.x = x;
this.y = y;
}
}
/*
선언된 Display 클래스를 React클래스 선언문 뒤에 Extends를 붙여
Display클래스를 상속 받고 있습니다.
*/
class React extends Display{
constructor(x, y, width, height){
/*
부모클래스의 생성자로 자식클래스에서 생성자 호출 시 부모 클래스가 초기화 되도록 강제적으로 super를 호출됩니다.
*/
super(x, y);
this.width = width;
this.height = height;
}
}
리액트에서는 JSX문법을 사용하는데, 이는 페이스북에서 만든 것으로 HTML과 비슷하게 생기고 비슷하게 사용하지만 전혀 다른 문법입니다.
JSX에서는 꼭 지켜야할 규칙들이 몇가지 있습니다.
import React, { Component } from 'react';
class App extends Component {
render() {
return (
<div>
<p>Hello world // 에러발생
<p>Hello world</p> // 정상작동
<input type='text' > 에러발생
<input type='text' /> // 정상작동
</div>
);
}
}
export default App;
리액트를 사용하기 위해서는 반드시 import React
를 선언해야합니다.
- 감싸져 있는 엘리먼트
두개 이상의 엘리먼트는 무조건 하나의 엘리먼트로 감싸져있어야 합니다.
import React, { Component } from ‘react’;
class App extends Component {
render() {
return (
<div>
<p> Hello world</p>
<p> Have a Nice day</p>
<div>
);
}
}
export default App;
// 리액트를 불러올 때 Component와 함께 Fragment도 불러와야 함
import React, { Component, Fragment } from ‘react’;
class App extends Component {
render() {
return (
<Fragment>
<p> Hello world</p>
<p> Have a Nice day :)</p>
</Fragment>
);
}
}
export default App;
import React, { Component } from 'react';
class App extends Component {
render() {
let name = 'react';
return (
<div>
<p>Hi {name}!</p>
</div>
);
}
}
export default App;
별도의 파일에 스타일을 정의해놓고, 리액트 컴포넌트 파일에서 정의한 css파일을 import합니다.
import './App.css' // 불러오기
html에서의 class는 className
return (
<div className="App">
Hello World
</div>
);
React DOM은 HTML 어트리뷰트(attribute) 이름 대신 캐멀케이(camelCase)를 네이밍 컨벤션으로 사용합니다. 예를 들어, JSX에서 tabindex는 tabIndex로 작성합니다.
class 어트리뷰트는 JavaScript의 예약어이므로 className으로 작성합니다.
아래 예제는 특정 값이 true일 경우에만 보여지고, false일 때 태그를 안보이게 하고 싶으면 아래 처럼 작성해도 됩니다.
import React, { Component, Fragment } from 'react';
class App extends Component {
render() {
const num = 1;
return (
<Fragment>
{
num === 1 && <div>1입니다.</div>
}
<div>Bye</div>
</Fragment>
);
}
}
export default App;
또 다른 예제는 조건이 여러개일 경우에는 아래처럼 즉시 함수 호출문을 작성하거나 ES6에서 자주 사용하는 화살표 함수를 사용하면 더 깔끔하게 조건 문에 따라서 값을 표현할 수도 있습니다.
import React, { Component, Fragment } from 'react';
class App extends Component {
render() {
const num = 1;
return (
<Fragment>
{
(() => {
if (num === 1) return <div>1이다</div>
if (num === 2) return <div>2이다</div>
if (num === 3) return <div>3이다</div>
return <div>없다</div>
})()
}
<div>Bye</div>
</Fragment>
);
}
}
export default App;
아래 예제는 html
import React, { Component } from 'react';
class App extends Component {
render() {
const style = {
backgroundColor: 'black',
padding: '1px',
color: 'green',
fontSize: '36px',
margin: '10px'
};
return (
<div style={style}>
안녕하세요.
</div>
);
}
}
export default App;
react에서 css에 정의한 클래스를 적용하는 방법은 아래와 같습니다.
먼저, App.css 파일을 하나 만들고 적용할 속성들을 정의합니다.
.App {
background: red;
color: aqua;
font-size: 36px;
padding: 1rem;
font-weight: 600;
}
App이라는 클래스를 정의하였습니다. 그리고 react로 해당 클래스를 아래 코드처럼 적용해주면 됩니다.
import React, { Component } from 'react';
import './App.css'; // css 파일을 import를 해줘야 합니다.
class App extends Component {
render() {
return (
<div className="App">
안녕하세요.
</div>
);
}
}
export default App;
기존의 javascript와의 차이점은 속성 명이 class가 아니고 className으로 명시해줘야 합니다. 물론 예전에는 class로 적으면 경고를 하였지만, 지금 최신 버전에서는 class라고 명시해도 적용이 됩니다.
일반적으로 자바스크립트로 주석을 달 경우에는 // 주석
으로 달고 있지만, react에서 사용하면 html 페이지에 그대로 렌더링이 됩니다.
멀티라인 주석도 예외가 아닙니다. 주석을 달기 위해서는 아래처럼 {}
괄호로 감싼 다음에 그 안에 멀티라인으로 주석을 달면 됩니다.
import React, { Component } from 'react';
import './App.css';
class App extends Component {
render() {
const style = {
backgroundColor: 'black',
padding: '1px',
color: 'green',
fontSize: '36px',
margin: 5 + 1 +'px'
};
return (
<div>
{/*멀티라인도 예외가 아니다.*/}
<h1
// 내가 여기에 주석을 쓸거다
>
리액트
</h1>
// 안녕
</div>
);
}
}
export default App;
가상 DOM은 리액트의 장점으로 실제 모델이 바뀔 때마다 브라우저에서 돔 트리를 생성하고, 랜더링 하는 과정이 반복되면 브라우저가 내부적으로 많은 연산을 하게 되는데 가상 DOM은 실제로
리얼 DOM에 바뀐 모델 부분을 다시 연산하는게 아니고 가상으로 DOM을 그려서 리액트가 리얼 DOM이랑 바뀐 부분을 캐치하여 바뀐 부분만 브라우저가 연산을 하도록 합니다.
이로 인해서 브라우저 성능이 개선되는 효과를 누릴 수 있습니다.