실전 리액트 프로그래밍 개정판 - 이재승 지음 (참고자료)
*리액트는 페이스북에서 개발하고 관리하는 UI 라이브러리다.
앵귤러가 웹 애플리케이션 개발에 필요한 다수의 기능을 제공하는 것과는 대조적으로, 리액트는 UI기능만 제공한다.
=> 전반적인 시스템을 직접 구축할 수 있으니 각자의 환경에 맞게 최적화할 수 있다.
가장 큰 이유 중 하나는 UI를 자동으로 업데이트해 준다는 점.
=> API 통신이나 사용자 이벤트를 통해 프로그램의 상탯값을 변경하면 리액트가 변경된 상탯값을 기반으로 UI를 자동으로 업데이트 한다.
리액트와 같은 도구를 사용하지 않으면 브라우저의 돔을 직접 업데이트해야 한다.
가상 돔은 이전 UI상태를 메모리에 유지해서, 변경될 UI의 최소 집합을 계산하는 기술이다.
=> 가상 돔 덕분에 불필요한 UI 업데이트는 줄고, 성능은 좋아진다.
리액트에서 코드를 작성할 때는 다음 조건을 지키는 게 좋다.
render 함수는 순수 함수여야 하므로 인수 state가 변하지 않으면 항상 같은 값을 반환해야 한다. 컴포넌트의 상탯값을 수정할 때는 기존 값을 변경하는 게 아니라 새로운 객체를 생성해야 한다.
=> 복잡도가 낮아지고, 찾기 힘든 버그가 발생할 확률이 줄어든다. 더 중요한 것은 리액트에서 이 두 조건을 따르면 렌더링 성능을 크게 향상 시킬 수 있다.
리액트는 UI 라이브러리이기 때문에 UI를 제외한 나머지 요소들은 개발자가 신경 써서 관리해야 한다. create-react-app과 같은 도구를 사용할 수도 있지만 직접 구축하면서 바벨과 웹펙을 알아가 보자.
https://unpkg.com/browse/react@16.14.0/umd/
https://unpkg.com/browse/react-dom@16.14.0/umd/
여기서 react.development.js
와 react.production.min.js
,
react-dom.development.js
와 react-dom.production.min.js
를 받는다.
그리고 같은 폴더에 내용이 없는 simple1.html, simple1.js 두 파일을 만든다.
simple1.html에 다음처럼 입하자.
<!-- simple1.html -->
<html>
<body>
<h2>안녕하세요. 저는 예흠이라고 해요. 좋아요 버튼 눌러 주세요!</h2>
<div id="react-root"></div>
<script src="react.development.js"></script>
<script src="react-dom.development.js"></script>
<script src="simple1.js"></script>
</body>
</html>
simple.js 파일에는 좋아요 버튼을 보여 주는 리액트 컴포넌트를 작성해 보자. 버튼을 누르면 좋아요 취소 문구를 보여 준다.
//simple.js
function LikeButton() {
const [liked, setLiked] = React.useState(false);
const text = liked ? '좋아요 취소' : '좋아요';
return React.createElement(
'button',
{ onClick: () => setLiked(!liked) },
text,
);
}
const domContainer = document.querySelector('#react-root');
ReactDOM.render(React.createElement(LikeButton), domContainer);
리액트로 만든 첫 번째 웹 페이지가 완성됐다.
페이지를 브라우저에 띄우면 좋아요 버튼이 보이고 클릭하면 좋아요 취소 버튼으로 바뀌는 것을 확인 할 수 있다.
createElement 함수의 구조는 다음과 같다.
React.createElement(component, props, ...children) => ReactElement
첫 번째 매개변수 component는 일반적으로 문자열이나 리액트 컴포넌트다.
=> 예를들어, 문자열 p를 입력하면 HTML p 태그가 생성된다.
두 번째 매개변수 props는 컴포넌트가 사용하는 데이터를 나타낸다.
=> 돔 요소의 경우 style, className 등의 데이터가 사용될 수 있다.
세 번째 매개변수 children은 해당 컴포넌트가 감싸고 있는 내부의 컴포넌트를 가리킨다.
div 태그가 두 개의 p 태그를 감싸고 있는 경우에 다음과 같이 작성할 수 있다.
<div>
<p>hello</p>
<p>yeheum</p>
</div>
createElement(
'div',
null,
createElement('p', null, 'hello'),
createElement('p', null, 'yeheum'),
)
바벨(babel)은 자바스크립트 코드를 변환해 주는 컴파일러다.
바벨을 사용하면 최신 자바스크립트 문법을 지원하지 않는 환경에서도 최신 문법을 사용할 수 있다.
리액트에서는 JSX 문법을 사용하기 위해 바벨을 사용한다.
=> babel이 JSX문법으로 작성된 코드를 createElement 함수를 호출하는 코드로 변환해 준다.
이제 최초의 외부 패키지로 바벨을 추가해 보자.
현재까지의 코드는 너무 단순하므로 그 전에 몇 가지 컴포넌트를 먼저 추가해 보자.
=> 화면에 count 상탯값을 보여 주고 증가, 감소 버튼을 통해서 count 상탯값을 변경하는 코드를 작성해자.
function LikeButton() {
//기존 코드와 같음
}
function Container() {
const [count, setCount] = React.useState(0);
return React.createElement(
"div",
null,
React.createElement(LikeButton),
React.createElement(
"div",
{ style: { marginTop: 20 } },
React.createElement("span", null, "현재 카운트: "),
React.createElement("span", null, count),
React.createElement(
"button",
{ onClick: () => setCount(count + 1) },
"증가"
),
React.createElement(
"button",
{ onClick: () => setCount(count - 1) },
"감소"
)
)
);
}
const domContainer = document.querySelector("#react-root");
ReactDOM.render(React.createElement(Container), domContainer);
simple3.html의 결과 화면이다.
단순한 기능인데도 UI코드가 상당히 복잡하다. 바벨의 도움을 받아서 이부분을 개선해 보자.
simple3.html 파일을 복사해서 simple4.html 파일을 만든다.
src 폴더를 만든후 simple3.js 파일을 복사해 simple4.js 파일을 src폴더 안에 넣어보자.
폴더 구조는 아래와 같다.
이제 createElement 함수를 호출하는 코드를 JSX 문법으로 변경해 보자.
function Container() {
const [count, setCount] = React.useState(0);
return (
<div>
<LikeButton />
<div style={{ marginTop: 20 }}>
<span>현재 카운트: </span>
<span>{count}</span>
<button onClick={() => setCount(count + 1)}>증가</button>
<button onClick={() => setCount(count - 1)}>감소</button>
</div>
</div>
);
}
JSX문법은 자바스크립트 표준이 아니기 때문에 simple4.js 파일을 그대로 실행하면 에러가 발생한다.
바벨을 이용해서 JSX 문법으로 작성된 파일을 createElement 함수로 작성된 파일로 변환해 보자.
다음 패키지를 설치해야 한다.
npm install @babel/core @babel/cli @babel/preset-react
설치된 패키지를 이용해서 자바스크립트 파일을 변환해 보자.
npx babel --watch src --out-dir . --presets @babel/preset-react
위 명령어를 실행하면 src 폴더에 있는 모든 자바스크립트 파일을 @babel/preset-react 프리셋을 이용해서 변환 후 현재 폴더에 같은 이름의 자바스크립트 파일을 생성한다. watch 모드로 실행했기 때문에 src 폴더의 자바스크립트 파일을 수정할 때마다 자동으로 변환 후 저장한다.
웹팩(webpack)은 자바스크립트로 만든 프로그램을 배포하기 좋은 형태로 묶어 주는 도구이다.
2000년대 초반의 웹 페이지는 페이지가 전환될 때마다 새로운 HTML 파일을 요청해서 화면을 새로 그렸다. 그 당시 자바스크립트는 돔을 조작하는 간단한 역할만 했기 때문에 코드의 양이 많지 않았다. 한두 개의 자바스크립트 파일을 HTML의 script 태그를 이용해서 서비스하는 방식이면 충분했다. Ajax가 유행했을 때는 자바스크립트의 비중이 조금 더 커졌지만 많아 봐야 페이지당 자바스크립트 파일 열 개 정도 수준이었다.
그런데 웹사이트 제작 방식이 단일 페이지 애플리케이션(single page application) 으로 전환되면서 상황은 달라졌다. 한 페이지에도 자바스크립트 파일이 수십 또는 수백 개 필요했기 때문에 더는 기존 방식이 통하지 않았다.
전통적인 방식으로 개발된 웹사이트의 HTML 코드와 같은 방식으로는 계속 늘어나는 자바스크립트 파일을 관리하기가 힘들다.
웹팩은 ESM(ES6의 모듈 시스템)과 commonJS를 모두 지원한다. 이들 모듈 시스템을 이용해서 코드를 작성하고 웹팩을 실행하면 예전 버전의 브라우저에서도 동작하는 자바스크립트 코드를 만들 수 있다.
웹팩을 실행하면 보통은 하나의 자바스크립트 파일이 만들어지는데, 원한다면 여러개의 파일로 분할할 수도 있다.
웹팩을 사용해서 리액트의 두 파일을 자바스크립트의 모듈 시스템으로 포함시켜 보자.
webpack-test라는 폴더를 만들고 그 폴더에서 다음 명령어를 실행한다.
npm init -y
명령어를 실행하면 package.json 파일이 만들어진다.
이 두 리액트 파일은 모듈 시스템을 이용해서 main.js 파일에 포함될 예정이다.
구조는 아래와 같다.
이제 필요한 외부 패키지를 설치해 보자.
npm install webpack webpack-cli react react-dom
웹팩과 함께 리액트 패키지도 설치했다. react 패키지에는 우리가 위에서 내려받았던 react.production.min.js, react.development.js 파일이 포함되어 있다. react-dom 패키지도 마찬가지다.
이전에는 url을 직접 입력해서 각각의 파일을 내려받았지만, 이제는 모듈 시스템과 npm 덕분에 외부 패키지를 프로젝트에 쉽게 포함할 수 있게 되었다.
먼저 index.js 파일에 다음 내용을 입력한다.
//index.js
import React from "react";
import ReactDOM from "react-dom";
import Button from "./Button";
function Container() {
return React.createElement(
"div",
null,
React.createElement("p", null, "버튼을 클릭해 주세요."),
React.createElement(Button, { label: "좋아요" }),
React.createElement(Button, { label: "싫어요" })
);
}
const domContainer = document.querySelector("#react-root");
ReactDOM.render(React.createElement(Container), domContainer);
Button.js 파일에는 Button 컴포넌트를 작성하고, ESM 문법을 이용해서 필요한 모듈을 가져오고 Button 컴포넌트를 내보내도록 하자.
//Button.js
import React from "react";
export default function Button(props) {
return React.createElement("button", null, props.label);
}
이제 웹팩을 이용해서 두 개의 자바스크립트 파일을 하나의 파일로 합쳐 보자.
npx webpack
위 명령어를 실행하면 dist 폴더 밑에 main.js 파일이 생성된다.
index.html을 실행해 보니 원했던 대로 잘 나온다.
웹팩에는 이 외에도 다양한 기능이 있다.
다음번 정복기에서 더 자세하게 알아보도록 하자.