Node.js는 웹 브라우저 이후 등장한 자바스크립트 런타임 이다.
자바스크립트 런타임이란 자바스크립트의 구동 환경이라는 뜻으로, 지금까지는 웹 브라우저가 유일한 자바스크립트 런타임이었으며, 그러므로 자바스크립트는 웹 브라우저 외에서는 사용할 수 없었다.
그런데 Node.js라는 독립적인 자바스크립트 런타임이 등장하면서 어떤 환경에서도 자바스크립트를 실행할 수 있게 되었고, 활용 범위가 넓어짐과 함께 자바스크립트를 사용하는 개발자도 늘어나 2022년 기준으로 자바스크립트는 개발자가 가장 많이 사용하는 프로그래밍 언어가 되었다.
Node.js는 단순히 자바스크립트 런타임이며, 서버 개발 기술은 아니다.
리액트 활용을 위해 Node.js의 학습이 선행되어야 하는 이유?
Node.js는 아래의 Node.js 홈페이지에서 다운받을 수 있다.
Node.js — Run JavaScript Everywhere (nodejs.org)
'Tools for Native Modules' 단계에서 'Automatically install the necessary tools. ...' 항목을 체크로 표시하고 진행해야 한다는 점에 유의하자!
설치가 완료되면 터미널을 열어 node -v를 입력해서 Node.js의 버전을 확인한다.
그리고 npm -v를 입력해서 npm(Node Package Manager)의 버전을 확인한다.
그리고 Visual Studio Code가 없다면 따로 설치한다.
console.log("Hello Borybop!");
node sample.js
패키지란? 여러 개의 자바스크립트 파일을 실행하고 관리하기 위한 일종의 관리 단위
복잡한 프로그램을 구현할 때는 보통 기능별로 파일을 나누어 작성하기 때문에, Node.js로 하나의 프로젝트에서 많은 자바스크립트 파일을 실행하려고 할 때는 여러 파일들을 하나의 패키지 형태로 구성하는 것이 편하다.
Node.js의 패키지를 직접 만들어 보자.
우선 VSCode 터미널을 열어 npm init을 입력한다.
이때 npm이란 Node Package Manager의 약자로, Node.js 패키지를 관리하는 도구를 뜻한다.
npm init이란 Node.js의 패키지를 초기화하는 명령어로, 여기서의 초기화란 일반적으로 사용하는 단어 초기화의 의미가 아닌 Node.js 패키지를 시작하는 데 필요한 최소한의 구성 요소를 자동으로 생성하는 과정을 말한다.
npm init을 입력하고 나면 package name을 입력하라는 안내가 나오는데, 위에서 문서 폴더 내에 생성한 새로운 폴더명(이하 루트 폴더)을 패키지명으로 적는다.
전부 설치되고 나면 yes를 입력해 초기화를 완료한다.
패키지 구성이 정상적으로 완료되면 VSCode에서 sample.js 말고도 package.json이라는 파일이 생성된 것을 확인할 수 있다. 이 파일에는 패키지의 메타 정보가 저장되어 있고, Node.js는 package.json에서 패키지 정보를 확인하여 그에 맞게 프로그램을 가동한다.
원래 index.js를 실행하기 위해 터미널에 node ./index.js라고 입력해야 했지만, scripts에 start 항목을 새롭게 추가하여 start를 node index.js와 같게 만들었기 때문에 npm run start만 입력해도 node ./index.js와 같은 역할을 수행한다.
모듈이란? 독립적으로 존재하는 프로그램의 일부인 파일로, 한 프로그램을 위해 만들었어도 다른 프로그램에서 또 사용할 수 있어 재활용 가능이라는 특징을 가진다.
모듈 시스템은 이러한 모듈을 사용하는 방법을 말하고, 자바스크립트에는 다양한 모듈 시스템이 있다.
그 중 ES 모듈 시스템이란 ECMAScript 모듈 시스템의 약자로, 줄여서 ESM이라고도 한다. 리액트, Vue와 같은 최신 프론트엔드 기술은 전부 ESM을 사용하지만 Node.js는 기본적으로 CJS 모듈 시스템을 사용하고 있다. 여기서 CJS는 CommonJS의 준말이고 ESM과 CJS 모듈 시스템은 문법 내용에 약간 차이가 있다.
그렇기 때문에 ESM을 사용하려면 package.json에서 설정을 변경해주면 된다.
ESM 문법으로 설정하기
아래와 같이 package.json에 , "type": "module"을 추가해 ESM 문법을 사용하자.
export 해보기
앞에서 말했듯 모듈은 재사용이 가능하다는 특징을 가지고 있고, 그렇기 때문에 특정 파일의 값이나 함수를 다른 파일에서 함께 사용해야할 때 편리하다. 하지만 특정 값이나 함수를 다른 파일에서 공유하려면, 먼저 공유를 설정하기 위해 해당 파일에서 내보내는 export 작업이 선행되어야 한다.
circle.js라는 파일을 새로 생성한 뒤 다음과 같은 코드를 입력하자.
export const PI = 3.141592;
export function getArea(radius) {
return PI * radius * radius;
}
export function getCircumference(radius) {
return 2 * PI * radius;
}
이때, circle.js에서 선언한 한 개의 상수와 두 개의 함수를 내보내려고 한다.
ESM에서는 다음과 같이 export 키워드를 변수나 함수 선언 앞에 붙이면 해당 값을 다른 모듈로 공유할 수 있다.
한 번에 여러 값을 내보낼 때는 다음과 같이 export로 값들을 묶어 한꺼번에 내보낸다.
import 해보기
이제 지금 모듈이 export한 값을 다른 파일(모듈)에서 import로 불러와 사용해 보자.
index.js의 내용을 전부 지운 뒤 다음과 같은 코드를 작성한다.
import { PI, getArea, getCircumference } from "./circle.js";
console.log(PI, getArea(1), getCircumference(1));
이것은 circle.js가 export했던 PI, getArea, getCircumference의 값을 import하는 코드이다.
터미널을 열어 npm run start 명령어를 입력하고 index.js를 실행한다.
....
여기서 오류가 났었는데 package.json을 제대로 수정하지 않았기 때문이다.
main 항목의 파일을 기존의 sample.js(생성 당시 하나밖에 없는 파일이었으므로 기본값)에서 index.js로 바꿨어야 했다.
"main": "index.js"가 되도록
전부 불러오기
값을 전부 불러와야 한다면, ESM 문법에 따라 import * as A from B 형식으로 많은 모듈을 한 번에 불러올 수 있다.
기본값으로 내보내기
ESM에서는 export 키워드 다음에 default를 붙여 해당 값을 모듈의 기본값으로 export할 수 있다.
이때 기본값으로 내보내는 값은 불러올 때 값의 이름을 명시하는 중괄호를 치지 않아도 되고, 모듈이 기본값으로 내보낸 값은 다른 모듈이 이 값을 불러올 때 자유롭게 다른 이름을 붙여 불러올 수 있다.
//export하는 파일에서...
export default 10; // 모듈의 기본값
//import하는 파일에서...
import name from './윗파일.js';
이때, 기본값으로 내보내지 않은 모듈에서 값을 기본값으로 불러오면 오류가 발생한다.
Node.js 패키지에서는 다른 사용자가 만들어 서버에 배포한 Node.js 패키지 파일인 외부 패키지를 설치해 사용할 수 있다.
외부 패키지를 이용하면 모든 기능을 사용자가 직접 개발하지 않아도 되며, 필요한 부분에 맞는 기능을 수행하는 외부 패키지를 설치하면 된다는 장점이 있다.
이러한 외부 패키지를 라이브러리라고도 한다. 라이브러리는 프로그램을 개발할 때 공통으로 사용할 수 있는 기능들을 모아 모듈화한 것으로, 특정 기능만을 수행할 뿐 완전한 프로그램은 아니다.
대부분의 라이브러리는 오픈소스로, 비용을 요구하지 않는다.
라이브러리 설치하기
아래 사이트에 접속해서 npm i lodash를 복사하고, VSCode의 터미널에서 pwd로 작업 경로를 확인한 다음 npm i lodash을 입력해 lodash를 설치한다.
제대로 설치가 끝나고 나면 3가지 변화가 일어나게 된다.
이 node_modules 폴더에는 패키지에 설치된 라이브러리가 실제로 저장된다. 그러므로 패키지에 이미 이 폴더가 있는 상황에서 새로운 라이브러리를 설치한다면 이 node_modules 폴더에 그 새로운 라이브러리의 폴더가 추가되는 것이다.
라이브러리 다시 설치하기. 왜?
node_modules 폴더는 용량이 크기 때문에 외부 패키지를 공유할 땐 보통 이 폴더를 제외하고 공유한다. 하지만 공유받은 사용자는 공유받은 패키지에 node_modules가 존재하지 않기 때문에 라이브러리를 사용할 수 없다. 따라서 이 라이브러리를 사용하기 위해서는 사용자가 자신의 터미널에서 npm install 명령을 수행하여 node_modules 폴더를 다시 설치받아야 한다. 이러면 공유받은 라이브러리의 package.json과 package-lock.json에 있는 정보를 토대로 node_modules 폴더를 다시 만든다. 너무 기특해!!
이때, package.json의 dependencies 항목에서 표시된 버전의 범위 또는 package-lock.json에 표시한 정확한 버전 이름을 이용해 node_modules 폴더에 필요한 패키지를 자동으로 설치한다.
실습을 위해 node_modules 폴더를 지우고 다시 설치해 보자.
라이브러리 사용하기
라이브러리를 불러올 땐 경로와 확장자를 명시하지 않아도 된다. 아래와 같이 import lodash from "lodash"로 lodash 라이브러리의 기본값을 변수 lodash에 저장하자. lodash의 uniqBy는 인수로 전달한 배열에서 중복값을 제거하고 반환하는 메서드이다.
리액트는 Node.js의 라이브러리 중 하나로, 복잡한 웹 서비스를 쉽고 빠르게 개발할 수 있도록 한다. 리액트를 통해 사용자와 웹서비스 간의 양방향 소통을 구현할 수 있고, 다양한 인터렉션을 구축할 수 있다.
리액트의 특징은 다음과 같다.
컴포넌트 기반의 유연성
리액트는 컴포넌트 개념을 채택하여 코드의 유연성 문제를 해결했기 때문에 새로운 기능을 추가하거나 기능을 업그레이드할 때 코드를 많이 수정하지 않아도 된다. 코드의 유연성 문제란 동일한 코드가 중복되는 문제로, 페이지 수가 많고 기능의 수정 및 추가가 잦은 대규모 어플리케이션을 구축할 때 여러 번 중복되는 코드는 좋지 않다.
리액트는 모듈화를 이용해 중복 코드를 제거하는데, 이는 여러 페이지에서 공통으로 사용되는 코드를 컴포넌트 단위의 모듈로 만들어 놓고 필요할 때 호출하여 사용한다. 이때 컴포넌트는 리액트를 대표하는 중요한 개념 중 하나로, 페이지를 구성하는 요소라는 의미가 포함되어 있다.
그래서 컴포넌트가 뭐냐? 리액트에서는 컴포넌트를 HTML 요소를 반환하는 함수라는 의미로 사용하고 있다. 한 페이지에서 생성한 컴포넌트는 다른 페이지에서도 불러와 사용할 수 있으며, 컴포넌트 내에서 코드를 수정하면 모든 페이지에 일괄적으로 자동 반영되므로 하나하나 고치는 수고가 덜하다는 장점이 있다.
컴포넌트는 각자 독립적인 기능을 수행하지만 여러 컴포넌트는 조화롭게 하나의 페이지를 구성한다.
쉽고 간단한 업데이트
업데이트란? 웹 페이지의 정보를 교체하는 일 (예시: SNS에서 게시글에 '좋아요' 클릭)
웹에서 페이지를 업데이트하려면 DOM(Document Object Model, 문서 객체 모델)을 조작해야 한다. DOM은 HTML 코드를 트리 형태로 변환한 구성물이다. DOM은 웹 브라우저가 직접 생성하며, 이는 HTML 코드를 렌더링, 즉 HTML+CSS+JS를 해석하고 실제로 표현하기 위함이다.
DOM은 DOM API(DOM Application Programming Interface)를 제공하는데, JS는 이 API를 통해 돔에 접근하고 요소를 추가/수정/삭제할 수 있다.
이때, API란 어떤 대상을 제어하기 위해 사용하는 도구로, DOM API는 JS를 이용해 DOM을 조작하는 다양한 기능을 지원하는 도구이다.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<script>
function onClickButton() {
const h1Elm = document.getElementById("h1"); ②
h1Elm.innerText = "Hello Hello!"; ③
}
</script>
</head>
<body>
<h1 id="h1">안녕하세요?</h1>
<button onclick="onClickButton()">인사해요!</button> ①
</body>
</html>
함수 해석
① 버튼을 클릭하면 함수 onClickButton()이 실행된다.
② document는 DOM을 의미하고, getElementById 메서드는 DOM에서 인수로 전달한 태그의 id요소를 찾아 반환한다. 따라서, 태그 <h1 id='h1'>은 상수 h1Elm에 저장된다.
③ innerText는 돔 요소의 텍스트로, h1Elm에 저장된 요소의 텍스트를 "반가워요!"로 변경한다.
이 코드를 실행하면 다음과 같이 제목과 버튼이 있는 페이지가 나타난다.
이처럼 JS로 DOM을 조작하면 페이지 전체를 새롭게 렌더링하여 업데이트된 페이지를 보여준다. 그러나 DOM에서 원하는 요소를 찾고 수정 사항을 반영하는 일은 트리 구조에 따라 복잡하고 어려워질 수 있다.
반면, 리액트는 사용자의 특정 행동이 일어나거나 데이터가 바뀌는 등 업데이트가 필요하면 교체해야 하는 요소를 삭제하고, 수정된 내용을 반영한 뒤 페이지를 통째로 다시 만들어 업데이트하므로 훨씬 간단하다. 그러므로, 리액트를 사용하면 복잡한 인터렉션을 지원하는 웹 서비스 개발에 집중할 수 있다.
빠른 업데이트
업데이트란 결국 브라우저가 페이지를 다시 렌더링하는 것인데, 업데이트를 할 때마다 페이지를 통째로 다시 만드는 리액트는 어떻게 이렇게 빠르게 업데이트할 수 있을까?
우선 브라우저는 렌더링되기 위해 4가지 단계를 거친다.
DOM이 변경되면 브라우저는 업데이트를 위해 위의 렌더링 과정을 다시 반복한다. 레이아웃과 페인팅 과정은 많은 연산을 동반하므로, DOM의 업데이트가 필요 이상으로 많아지면 브라우저의 성능이 떨어지고 이는 랙 현상 또는 응답 불능 상태로 연결된다.
리액트는 실제 돔의 사본인 Virtual DOM을 활용하는 것으로 이런 문제를 해결했다. 페이지에 변경 사항이 발생하면 먼저 Virtual DOM에 모아놨다가, 필요할 때 한꺼번에 실제 DOM을 업데이트하는 방식이다. 그러므로 Virtual DOM에는 변경사항이 차곡차곡 쌓이지만, 실제 DOM에서는 가만히 있다가 한꺼번에 여러 변경이 일어나는 것이다. 이러면 업데이트가 잦아도 실제 브라우저의 성능은 떨어지지 않는다.
이렇게 페인팅과 레이아웃을 여러 번 수행하지 않고, 변경사항을 모았다가 업데이트가 필요할 때 한 번에 처리하는 것으로 리액트는 더 효율적이고 빠른 업데이트를 지원한다.
리액트 앱이란? 리액트로 만든 웹 서비스인데, 마치 사용자와 실시간으로 상호작용하는 응용 프로그램(어플리케이션)처럼 다양한 상호작용을 제공하기 때문에 리액트 웹이 아닌 리액트 앱으로 부른다.
Create React App
Node.js의 라이브러리 중 하나인 Create React App(이하 CRA)은 보일러 플레이트의 일종으로, 쉽게 프로젝트를 생성하도록 돕는 개발 도구이다.
Create React App를 설치하기 위해, 문서 아래에 새로운 폴더를 만든 다음 바로 터미널을 열고 npx create-react-app . 을 입력한다. 이 때, 점은 현재 폴더를 의미한다.
아.. 근데 이때 문제가 발생했다.
왜지? 그래서 찾아봤다.
npm install create-react-app 명령어를 먼저 입력해야 한다고 한다.
왜지?? 이유를 찾지 못했지만 그냥 하라니까 해본다. 아마 저자의 라이브러리엔 CRA가 이미 있어서 현재 폴더에 풀면 됐고, 난 어떤 이유로 없어서 install 단계부터 했어야 하는 게 아닐까 싶다.
설치가 완료되면 happy hacking!이라는 문구와 함께 pwd로 현재 경로를 확인하고, npx create-react-app test를 입력해보라는 안내가 나온다. 해당 명령어를 차례로 입력하면 현재 경로 아래에 test라는 폴더가 생기고 거기에 리액트 앱이 설치된다. 이는 위에서 저자가 안내한 npx create-react-app . 과 동일한 명령어이며, 그냥 현재 경로말고 test 폴더에 풀어서 현재 경로를 뜻하는 점 대신 test가 된 것이다.
이렇게 설치가 완료되면 해당 폴더에 새로운 폴더와 파일이 생기면서 웹으로 아래와 같은 리액트 화면이 실행된다.
리액트 앱의 구성 요소
리액트를 설치하면서 폴더에 만들어진 요소들을 살펴보자! 아래는 리액트가 설치되며 당시 작업 경로에 새롭게 생긴 파일들이다. 이것들은 리액트 앱의 구성 요소로, CRA는 리액트 앱을 생성함과 동시에 앱이 동작하는 데 필요한 파일과 폴더를 자동으로 생성하는데, 이런 파일과 폴더 모음을 템플릿이라고 한다. CRA도 Node.js 패키지이기 때문에, 이 test폴더 아래에는 package.json, package-lock.json, node_modules와 같은 Node.js 패키지 구성 파일이 존재한다.
따라서, package.json의 "dependencies" 항목을보면 CRA로 생성한 리액트 앱에 어떤 라이브러리가 설치되었는지, 리액트 버전은 몇 버전인지 등에 대한 정보가 들어있다는 것을 알 수 있다.
public 폴더엔 리액트에서 공통으로 사용하는 폰트 파일, 이미지 파일 등을 저장하고, 기본으로 포함된 파일이 있다.
src(source) 폴더는 프로그래밍 소스를 저장하는 폴더로, 프로젝트에서 사용할 소스 파일을 저장할 수 있어 리액트를 사용하는 동안의 자바스크립트 파일들을 여기에 모아놓는다.
리액트 앱 실행하기
package.json의 scripts를 확인하면 "start": "react-scripts start", 즉 start 명령으로 리액트 앱을 실행하는 스크립트가 작성되어 있다. VSCode의 터미널을 열어 npm run start를 입력하여 해당 스크립트를 실행하자.
현재 위치가 test 폴더가 아닌 test의 상위 폴더인 Borybop2로 되어 있기 때문이다. cd test로 작업위치를 옮기고 다시 시도해봤다. 깜빡했네.. 항상 pwd를 확인하는 습관을 가져야겠다.
위 화면은 CRA가 설정한 초기의 템플릿 페이지이며, 당연히 사용자 하기에 따라 얼마든지 변경할 수 있다. 이렇게 터미널에서 실행 중인 리액트 앱을 종료하려면 <Ctrl> + <C>를 누르고, 일괄 작업을 끝내시겠습니까? 에서 Y를 입력하여 종료한다. 리액트 앱을 종료하면 브라우저에서 실행되고 있는 http://localhost:3000과의 접속 또한 자동으로 종료되고, 종료 후 브라우저에서 새로고침을 하면 사이트에 연결할 수 없다는 메시지가 뜬다.
리액트 앱으로의 접속
위에서 말한 것처럼, 리액트 앱으로 접속하기 위해서 우리는 3가지 단계를 거친다.
CRA로 만든 리액트 앱에는 웹 서버가 내장되어 있어, npm run start를 입력하면 앱에 내장된 웹 서버가 브라우저로 리액트 앱에 접속하게끔 동작한다. 그러므로, 브라우저는 내장된 웹 서버 주소에 자동으로 접속한다. 이때 기본 포트 번호는 3000번이고, http://localhost:3000이란 결국 앱에 내장된 웹 서버 localhost의 3000번 포트로 접속을 요청하는 것이다.
리액트 앱 동작 원리 자세히 보기
리액트 앱을 실행하면 기본으로 브라우저에 리액트 로고 페이지가 뜨고, 하단에는 'Edit src/App.js and save to reload'라는 문장이 나온다. 이것은 src 폴더의 App.js 파일을 수정하고 저장해서 다시 로드하라는 뜻이다.
App.js를 열고 App함수 중 return문 내의 코드를 수정한 뒤 저장하면 페이지의 렌더링 결과가 달라지게 된다. 이 함수 App처럼 HTML을 반환하는 JS함수는 컴포넌트이고, 함수 App은 즉 App 컴포넌트가 된다.
리액트 앱의 동작 순서는 다음과 같다.
위와 같은 과정은 http://localhost:3000에서 개발자 도구를 열고 [Elements] 탭에서 확인할 수 있는데, 리액트의 루트 요소로 사용된 <div id="root"> 아래에 App 컴포넌트가 반환하는 HTML 요소가 추가되어 있다.
!!!!! QUIZ !!!!!!
01. Node.js는 자바스크립트 런타임이면서 서버 개발 기술이기도 하다. (O/X)
02. VSCode에서 터미널 창을 여는 단축키는 <Ctrl> + < _ >이다.
03. package.json에서의 _ _ _ _ 항목은 패키지의 쉬운 사용을 위해 지정한 매크로 명령어를 저장한다.
04. Bee, Butterfly, Flower이라는 개별적인 값을 한꺼번에 내보내는 코드를 한 줄로 작성하라.
05. 일반적으로, _ _ _ _ _를 공유받았을 때 node_modules 폴더를 다시 설치해야 한다.
06. lodash 라이브러리에서 불러온 기본값을 변수 lodash에 저장하는 코드를 한 줄로 작성하라.
07. React는 Node.js의 _ _ _ _ _이다.
08. React에서의 컴포넌트란 _ _를 뜻한다.
09. JS와 달리, React는 교체가 필요한 요소를 삭제하고 새로운 수정 사항을 반영해 페이지를 통째로 _ _ _ _한다.
10. React를 설치하며 생긴 _ _ 폴더에 자바스크립트 파일 등 프로그래밍 소스를 저장할 수 있다.
정답: X / J / 스크립츠 / export { Bee, Butterfly, Flower }; / 외부 패키지 / import lodash from "lodash"; / 라이브러리 / 함수 / 업데이트 / 소스
출처: 이정환, 『한 입 크기로 잘라먹는 리액트』, 프로그래밍 인사이트(2023), https://reactjs.winterlood.com/., 코딩 낙서, 'React npx create-react-app 오류', React npx create-react-app 오류 :: 코딩 낙서 (tistory.com) (23.07.30)
Corner React.js 2
Editor: 보리밥
[React.js 2팀] 5장. 리액트의 기본 기능 다루기 (1) (0) | 2024.11.08 |
---|---|
[React.js 2팀] 1장. 자바스크립트 기초 -함수 ~ 2장. 자바스크립트 실전 -반복문 응용하기 (0) | 2024.09.27 |