React 입문(1) : Install ~ props (last update: 2020.12.14.)

devpark·2020년 12월 14일
0

React.js & JavaScript

목록 보기
1/11
post-thumbnail

Introduction

비공개 Notion에 학습한 내용들을 꾸준히 백업하고 있지만, 보다 공개적으로 학습할 필요가 있음을 느껴 다시 Velog로 돌아왔다. 마침 내가 React를 학습하고 있는 강좌와 책을 출판한 VELOPERT 김민준 저자가 개발한 블로그이기도 하고, 무엇보다 마크다운 문법을 지원하는 가벼운 블로그 플랫폼으로 아직까진 Velog만한 것이 없는 것이 사실이다.

이 글에서는 Velog의 개발자, Velopert 김민준 저자가 출판한 리액트를 다루는 기술 개정판(2019)누구든지 하는 리액트 강좌를 통해 기초부터 실무에 필요한 기술까지 직접 다루고 익혀보도록 한다.

누구든지 하는 리액트: 초심자를 위한 리액트 핵심 강좌
리액트를 다루는 기술 - 교보문고


주: 이 시리즈는 아래의 Notion 링크에서 한 페이지로 보실 수 있습니다.
Notion 정리 링크


0. Development Environment Setup

0-1. Installation

  1. Install Node.js also npx, Yarn.
    https://nodejs.org/en/download/
    https://classic.yarnpkg.com/en/docs/install/#windows-stable

  2. Install IDE (e.g. Visual Studio Code).

  3. Install Git Bash for Command-line Coding

0-2. Type Command and Access

  1. Type Command: npm install -g create-react-app or yarn global add create-react-app
  2. Type Command: create-react-app hello-react
  3. Type Command: cd hello-react yarn start
  4. access to http://localhost:3000 for check the result.

1. Theory & Background Knowledge

1-1. JSX (JavaScript XML)

JSX, 즉 JavaScript XML은 함수 호출과 객체 생성을 위한 문법적 편의를 제공하는 JavaScript의 확장으로, 특히 React.createElement() 호출을 반복해야 하는 불편을 해소한다. Template Engine이나 HTML 와 유사하게 보이지만, JSX는 React Element를 생성하면서 JavaScript의 모든 기능을 쓸 수 있도록 도와준다. 이를 통해 Developer Experience(개발자 경험)의 개선 등을 꾀할 수 있으며, 표현력이 뛰어나 코드를 읽기 쉽고, JSX는 XML과 문법이 유사하여 중첩된 선언형 구조를 더 잘 나타낸다. 참고로 JSX는 React 개발 시의 필수 항목은 아니다. 단, React 개발의 생산성 및 효율 증진을 위하여 사용이 매우 권장되고 있다.

1-2. Rules of JSX

이러한 JSX 개발을 위해 반드시 지켜야 하는 몇 가지 룰이 존재한다:

1. tags는 반드시 닫혀 있어야 한다.

input, br 등을 포함하여 종료 태그가 필요치 않은 단일 태그의 경우를 포함한다. 태그가 닫히지 않은 경우 Failed to compile. Syntax error : Unterminated JSX contents 에러가 발생한다.

2. 복수의 element는 반드시 하나의 element로 감싸 놓아야 한다.

e.g.

import React, { Component } from 'react';
class App extends Component{
	render(){
		return(
			<div>		
				The First Content on Here
			</div>
			<div>
				The Second Content Here
			</div>
		);
	}
}
export default App;

위와 같은 코드를 작성한 경우, Syntax error: Adjacent JSX elements must be wrapped in enclosing tag 이라는 에러가 발생한다. 이를 해결하기 위해서는 가장 간단하게 하나의 div, 또는 <React.Fragment></React.Fragment>등으로 자식 요소들(child elements)을 감싸면 해결된다. <React.Fragment>는 html 코드를 작성할 때 Outermost Wrapper Container div에 해당한다고 생각하면 쉽다. 이는 단순하게 요소들을 감싸기 위한 용도로, 스타일 관련 설정에서 별도의 번거로운 꼬임이나 설정 등과 무관하므로 편리하다. (참고로 Fragment는 v16.2에 도입되었다.)

3. JavaScript를 JSX 내부에 사용하는 경우 :

import React, { Component } from 'react';
class App extends Component {
	render(){
		const value = 'JAVASCRIPT VALUE ON HERE';
		return(
			<div>
				result : { value }
			</div>
		);
	}
} 
export default App;

const(상수)를 통해 변수를 선언하고 이를 호출하는 경우에는 render(){}의 내부에 변수를 선언하도록 하며, 이 변수를 호출하고 사용할 때에는 { VAL-NAME } 의 형식으로 작성하면 된다.

4. Conditional Rendering

JSX(JavaScript XML) 내부에 Conditional Rendering(조건부 렌더링)을 할 때는 보통 Ternary Operator(삼항 연산자) 또는 AND(&&) 연산자를 사용한다. 반면에, if Statement를 사용할 수는 없다. (필요한 경우 IIFE-Immediately Invoked Function Expresion- 함수로 대체한다.)

먼저 삼항 연산자를 보자 :

import React, { Component } from 'react';
class App extends Component{
	render(){
		return(
			<React.Fragment>
				<div>
					{
						1+ 1 === 2		
							? (<div> CORRECT </div>)
							: (<div> WRONG </div>)
					}
				</div>
			</React.Fragment>
		);
	}
}
export default App;

Ternary Operator는 값이 true/false일 때 각각에 해당되는 도출 값을 설정할 수 있다. 반면, true일 때만 값을 도출하고 false의 경우를 무시하려면 아래와 같이 AND(&&) 연산자를 사용하면 된다.

import React, { Component } from 'react';
class App extends Component{
	render(){
		return(
			<div>
				{
					1 + 1 === 2 && (<div> CORRECT </div>)
				}
			</div>
		);
	}
}
export default App;

단, 복잡한 조건문의 작성이 필요한 경우는 JSX 외부에서 로직을 작성하는 것이 권장되며 반드시 JSX 내부에서 작성해야 하는 경우 IIFE(Immediately Invoked Function Expression)를 사용하도록 한다.

IIFE 함수를 통한 코드의 예시는 아래와 같다 :

import React, { Component } from 'react';
class App extends Component {
	render(){
		const val = 1;
		return(
			<div>
				{
					// Method 1. IIFE (Immediately Invoked Function Expression)
					(function(){
						if (val === 1) return (<div> ONE </div>);
						if (val === 2) return (<div> TWO </div>);
						if (val === 3) return (<div> THREE </div>);
					})()
					// Method 2. Arrow Functions
					(() = > {
						if (val === 1) return (<div> ONE </div>);
						if (val === 2) return (<div> TWO </div>);
						if (val === 3) return (<div> THREE </div>);
					})()
				}
			</div>
		);
	}
}
export default App;

Method 2에서 작성된 Arrow Functions(화살표 함수)는 Anonymous Function(익명 함수)이기도 하다. ES6에서 자주 사용하는 문법이니 눈 여겨 봐두자.

5. Applying Style and className

JSX에서 style과 CSS class를 설정할 때는 다음과 같이 작성할 수 있다:

import React, { Component } from 'react';
class App extends Component{
	render(){
		const style = {
			backgroundColor: 'black',
			padding: '16px',
			color: 'white',
			fontSize: '12px'
		}
		return(
			<React.Fragment>
				<div style={ style }>
					hey
				</div>
			</React.Fragment>
		);
	}
}  
export default App;

HTML에서는 style 설정을 작성할 때 개별의 텍스트 형식으로 작성하였으나, react에서는 객체의 형태로 작성해야 한다. 이는 style 설정을 대입할 때 이를 객체 단위로 대입만 해 주면 되기 때문에 반복되는 코드를 줄이기 쉽다. 객체 내부에 각 속성을 선언 할 때 항목은 camel Casing으로 작성하고, 그의 속성 값을 ''(Quotation Mark) 내부에 작성해 준 후 이들을 대입할 요소에 style= { 스타일 객체명 }을 대입해 주면 끝이다. 쉽다. 또한 HTML에서의 class 대신 className을 사용한다. 이는 용어의 차이일 뿐 style 대입법은 HTML과 같다.

6. Commenting in JSX

주석은 다음과 같이 작성한다 :

import React, { Component } from 'react';
class App extends Component {
	render(){
		return(
			<div>
				{/* MULTI-LINE COMMENTS ON HERE */}
					<p // IN-TAGS COMMENTS ON HERE 

					CONTENT</p>
			</div>
			);
		}
	}
export default App;  

1-3. Background Knowledge : ES6

const, let, static const

const는 ES6(ECMA Script6)에 도입된 키워드로, 한 번 선언하고 바뀌지 않는 값(상수)을 설정할 때 사용한다. 즉, java에서의 final과 유사하다고 보면 된다. 이와 반대로 바뀌게 될 수 있는 값(변수)는 let을 사용하여 선언한다. 상수/변수로 나누어 선언한다는 점을 제외하고 기존 javaScript의 var와 유사해 보이나, scope의 단위가 다르다. 기존의 var는 Function-Scope로써, Hoisting의 영향, undefined의 값 도출 등 많은 문제를 가지고 있었다. 하지만 const/let은 Block-Scope 이므로 이와 같은 문제들이 개선되었다. ES6를 사용하는 동안 var를 쓸 일은 없으며, const(상수)와 let(변수)를 활용하면 된다.

요약하면 이들은 다음과 같이 사용할 수 있다:

const : invoke final-val : external linkage
static const : invoke final-val : internal linkage
let : invoke variables


2. Syntax

2-1. Importing / Exporting

import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';

먼저 import React, { Component } from 'react';는 react와 그 내부의 Component(구성 요소)를 불러오기 위함으로, 파일에서 JSX를 사용하려면 반드시 React를 import 하여야 한다. 입문 초기임으로 자동 import 문에 의존하지 말고 직접 타이핑하는 습관을 들이도록 한다. 두 번째 코드 import logo from './logo'는 이미지 파일 또는 svg 등을 불러오기 위함이며, 세 번째 코드 import './css'는 css Stylesheet를 불러오는 코드이다.

이는 React가 Webpack을 사용하기 때문에 가능한 작업이다. 이렇게 import문을 작성하게 되면 이 후 프로젝트를 build하는 경우, webpack에서 파일의 확장자에 따라 다른 작업을 하게 된다. css 파일을 불러오게 되면, 이후 프로젝트에서 사용한 프로젝트를 한 파일에 모두 결합하는 작업을 진행하고, js 파일을 불러오게 되면 모든 코드들이 제대로 로딩되도록 순서를 설정하고 하나의 파일로 merge해 준다. 또한 svg와 같이 사전에 설정하지 않은 확장자의 경우 파일로 import한 후 특정 경로에 사본을 만들게 되고, 해당 사본의 경로를 텍스트로 받아오게 된다.


2-2. Generating Components

...
class App extends Component{
	render(){
		return(
		<React.Fragment>
			<div className="App">
				CONTENT ON HERE
			</div>
		</React.Fragment>
		);
	}
}
export default App;

Component를 생성하기 위한 방법은 두 가지가 존재하는데: 위의 코드와 같이 class를 통해 생성하는 것이며 두 번째는 함수를 통해 생성하는 것이다. Class를 통해 생성하는 경우 반드시 render(){} 함수가 존재해야 하며, 그 내부에는 JSX를 return 해야 한다. 이와 같이 생성된 Component는 export default App을 통해 다른 곳에서 불러와 사용할 수 있도록 export하는 역할을 수행한다. 예를 들어, index.js 파일을 보면 다음과 같은 코드가 존재하는 것을 확인할 수 있다:

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
ReactDOM.render(<App />, document.getElementById('root'));
registerServiceWorker();

위의 코드 중, 생성한 Component를 불러오는 구문은 import App from './App'; 이다. 즉, 해당 import문의 문법은 import COMPONENT-NAME from './COMPONENT-PATH'; 로 이해하면 쉽다.

또한 브라우저 상의 react Component를 보여주기 위해서는 ReactDOM.render 함수를 사용한다. 이 중 첫 번째 인자는 렌더링 할 결과물이고, 두 번째 인자는 Component를 어떠한 DOM에 그릴지 정하게 된다.


2-3. props & state

React Component에서 다루는 데이터는 props와 state로 나뉜다. 이 중 props는 Parent Component가 Child Component에게 부여하는 값이다. Child Component에서는 props를 받아오기만 하고, 받아온 props를 직접 수정할 수는 없다. 단, state는 Component 내부에서 선언하여 값을 변경하는 것이 가능하다.

1. Class Components

먼저 Class를 통해 Component를 생성하는 경우는 다음과 같다:

	// 1. Generate new js File : COMPONENT-NAME.js
import React, { Component } from 'react';
class MyName extends Component{
	render(){
		return(
			<div>
				The Name is { this.props.name } . 
			</div>
		);
	}
}
export default MyName;
// 2. also add importing-statement in App.js
import React, { Component } from 'react';
import MyName from './MyName';
class App extends Component{
	render(){
		return(
		<myName name="React" />
		);
	}
}
export default App;

결과물:

또한 props에 값이 대입되지 않는 경우를 대비하여 defaultProps를 설정 및 대입할 수도 있다.
그 문법은 다음과 같다 :

// Component : MyName.js
import React, { Component } from 'react';
class MyName extends Component{
	// Method 1. invoke defaultProps to static
	static defaultProps = {
		name: 'defaultName'
	}
render(){
		return(
			<div>
				The Name is { this.props.name }  
			</div>
		);
	}
}
// Method 2. invoke defaultProps at out of class
MyName.defaultProps = {
	name: 'defaultName'
};
export default MyName;

즉, Class를 통해 새로운 Component를 생성하고
import 및 prop을 대입하는 것은 다음의 순서로 진행하면 된다 :

1. Component js 파일 생성
1-1. Importing-Statement : import React, { Component } from 'react'; 작성
1-2. extends Component
1-3. Component의 구성 내용 및 props가 대입될 구역 설정 e.g. {this.props.PropName}
1-4. defaultProps 설정 (Optional)

  import React, { Component } from 'react';
  class ComponentName extends Component{
  	render(){
  		return(
  			<div>
  				CONTENT ON HERE
  			</div>
  		);
  	}
  }
  export default ComponentName;

2. App.js에서 생성한 Component 호출 및 props에 값 대입
2-1. Importing Statement : import ComponentName from './ComponentName'; 작성
2-2. extends Component 작성
2-3. 해당 Component 호출 e.g. <ComponentName />
2-4. props에 값 대입 (optional)

import React, { Component } from 'react';
import ComponentName from './ComponentName';
class App extends Component{
	render(){
		return(
		<div>
			<ComponentName PropName="PROPERTIES ON HERE" />
		</div>
		);
	}
}
export default App;

2. Functional Components

단순히 props만 받아와서 화면에 노출하는 Component의 경우는 함수의 형태로(Functional) 다음과 같이 보다 간편한 문법으로 작성할 수 있다.

import React from 'react';
const propName = ({ propName }) => {
	return(
		<div>
			The Name is { propName } .
		</div>
	);
};
export default ComponentName;

Functional Component와 Class Component의 주요한 차이점은, state와 LifeCycle의 사용 여부이다. 따라서 함수형 컴포넌트의 초기 마운트가 아주 미세하게 빠르고, 메모리 자원을 다소 덜 사용하나 그 속도의 차이는 매우 미세하므로 컴포넌트를 무수히 많이 렌더링 하지 않는 이상 성능적으로 대단한 차이는 없다.

profile
아! 응응애에요!

0개의 댓글