성빈
JSX를 사용하는 리액트 본문
목차
- JSX
- Babel
- JSX 활용 예제 : Recipe
- React Fragments
- 웹팩
- 프로젝트 구성하기
JSX를 사용하는 리액트
JSX
자바스크립트 코드 안에서 바로 태그 기반의 구문을 써서 리액트 엘리먼트를 정의할 수 있게 해주는
JavaScript의 확장 문법 (JavaScript XML)
- HTML 코드를 작성하는 방법과 유사
- JSX는 자바스크립트이므로 자바스크립트 함수 안에서 JSX를 직접 사용할 수 있다.
- 직관적이고 가독성이 좋음
- element를 객체로 다루며, 표현식 포함 가능
- 변수 할당, 매개변수 전달, 함수 반환 등 일반 JavaScript 표현식으로 활용 가능
○ 리액트 엘리먼트 표기
React.createElement(IngredientsList, {id:"1", ...}, children);
○ JSX 표기
<IngredientsList id="1" ...>
<Ingredient />
<Ingredient />
</IngredientsList>
JSX 활용 예제
(예제 1)
(예제 2)
- 리액트 엘리먼트 사용
function IngredientsList(props) {
return React.createElement(
"ul",
{className: "ingredients"},
props.items.map( (ingrd, i) =>
React.createElement("li", {key: i}, ingrd) )
);
}
- JSX
위와 동일한 코드이지만, 훨씬 더 직관적이다.
function IngredientsList(props) {
return (
<ul class="ingredients">
{ props.items.map(
(ingrd, i) => <li key={i}> {ingrd} </li> )}
</ul>
);
}
babel
JSX는 깔끔하고 읽기 쉽지만 브라우저는 JSX를 해석할 수 없다.
createElement나 팩토리를 사용해 모든 JSX를 변환해야 하는데, 이때 쓸 수 있는 것이 바벨이다.
babel
코드 변환의 필요성 → babel 활용
- JavaScript 최신 문법의 활용과 호환성
(최신 문법을 지원하지 않는 하위 브라우저를 위한 하위 호환성) - JSX 코드를 리액트 코드로 변환
babel 사용법
- 스크립트 타입 선언
<script type="text/babel>
- CDN 링크를 HTML에 포함
<script src="https://unpkg.com/babelstandalone@6.15.0/babel.min.js">
babel 활용
JSX 활용 예제 : Recipes
- data는 2개의 객체를 포함한 배열이다.
- 각 객체에는 조리법의 이름, 필요한 조리법의 이름, 필요한 재료리스트, 조리 절차가 들어 있다.
- 조리법의 이름 - 문자열
- 필요한 조리법의 이름 - 배열이면서, 3개의 속성을 갖는 객체
<!-- Root element -->
<div id="root"></div>
<!-- React Library, React DOM & babel-->
<script src=react.js, react-dom.js, babel.js></script>
<script type="text/babel">
/* ch05/02/01-recipe.html */
// data : 조리법 객체의 배열
const data = [ ... ];
// component : Menu, 조리법 하나를 표현하는 함수 컴포넌트
const Recipe = function({name, ingredients, steps}){
return (
<section>
<h1>{name}</h1>
<ul>
{ingredients.map( (ingrd, i) =>
(<li key={i}>{ingrd.name}</li>) )}
</ul>
<section>
<h3>recipe</h3>
<ul>
{steps.map( (step, i) =>
(<p key={i}>{step}</p>) )}
</ul>
</section>
</section>
);
}
// component : Recipe, 조리법으로 이뤄진 메뉴를 표현하는 함수 컴포넌트
const Menu = function(props){
return (
<section>
<header>
<h1>{props.title}</h1>
</header>
<div className="recipes">
{ props.recipes.map( (recipe, i) =>
(<Recipe key={i}
name={recipe.name}
ingredients={recipe.ingredients}
steps={recipe.steps} />) ) }
</div>
</section>
);
}
// rendering : Menu를 현재의 DOM 안에 렌더링
ReactDOM.render(
<Menu recipes={data} title="recipes" />,
document.getElementById('root')
)
</script>
- Menu 함수 컴포넌트의 Recipe에 레시피별 내용을 다 구현해도 되지만 복잡해지니까
각 레시피를 표현하기 위한 Recipe 컴포넌트 구현 - name, ingredients, steps와 같이 객체로서 파라미터를 전달받으면,
객체의 구조분해 할당에 의해서 각각을 변수로 활용할 수 있다.
React Fragments
(예제1)
▶ 컴포넌트의 최상위 노드가 하나일 때에는 문제가 없다.
(예제 2)
▶ 문제 : 컴포넌트의 최상위 노드가 둘 이상일 경우, 닫힘 태그로 닫아줘야 한다는 오류 발생
▶ 해결 방법 : 리액트는 둘 이상의 인접한 형제 엘리먼트를 컴포넌트로 렌더링하지 않기 떄문에,
<div>와 같은 태그로 둘러싸야만 한다.
(예제 3)
▶ 문제점 : 아무 목적도 없는 불필요한 태그 발생
▶ 해결 방법 : <React.Fragment> 태그 사용
(예제 4)
▶ 결과 : 여러 개의 elements를 사용하되, 오른쪽 사진과 같이 DOM에는 명시적으로 태그를 만들지 않는다.
(위 코드와 동일, 코드 축약 가능)
Webpack
● 웹팩 = 모듈 번들러
여러 다른 파일들을 dependency graph를 연결하여 하나의 파일로 묶어 번들 생성
● 모듈화
- 장점
재사용성, 관리의 용이성 - 성능
의존 관계가 있는 여러 파일 번들로 묶으면, 브라우저가 한번만 읽기 때문에 네트워크 성능에 유리
프로젝트 설정하기
프로젝트 구성
수동으로 프로젝트 생성하는 방법
1. 프로젝트 생성
npm init -y
-y : 모든 디폴트 값을 사용한다.
package.json 파일을 열면 아래와 같은 파일이 출력된다.
2. 필수 패키지 설치
npm install react react-dom serve
react, react-dom, serve 패키지를 설치한다.
3. 컴포넌트 생성
Menu 컴포넌트와 Recipe 컴포넌트를 생성한다.
import React from "react";
import Recipe from "./Recipe";
export default function Menu(props){
return (
<section>
<header>
<h1> {props.title} </h1>
</header>
<div className="recipes">
{
props.recipes.map( (recipe, i) => (
<Recipe key={i} {...recipe} />
))
}
</div>
</section>
);
}
import React from "react";
export default function Recipe({name, ingredients, steps}){
return (
<section id={name.toLowerCase().replace(/ /g, "-")}>
<h1>{name}</h1>
<ul className="ingredients">
{ingredients.map( (ingrd, i) => (
<li key={i}>{ingrd.name}</li>) )}
</ul>
<section>
<h3>recipe</h3>
<ul>
{steps.map( (step, i) => (<p key={i}>{step}</p>) )}
</ul>
</section>
</section>
);
}
- Menu 컴포넌트
페이지의 전체적인 구성을 보여줌
외부에서 활용할 수 있도록 모듈로 배포
- Recipe 컴포넌트
조리법 제목 표시, 재료들의 ul 만들기, 조리 절차의 각 단계를 p 엘리먼트로 만들기
이 컴포넌트를 Recipe.is 파일에 넣어야 한다. → JSX를 사용하는 파일마다 맨 위에 react를 import하는 문장 필요
4. entry point (index.js), 데이터 (recipes.json) 생성
- entry point (index.js)
Main 코드
- 데이터 생성 (recipes.json)
객체의 형태로 저장이 되어있어, 객체의 구조분해 할당으로 데이터를 참조할 수 있다.
5. 개발환경 구성
5-1. 웹팩 빌드 만들기
V 웹팩으로 정적인 빌드 프로세스를 만들기 위해 필요한 모듈을 설치한다.
npm install -D webpack webpack-cli
- 이 앱의 시작 파일은 index.js이다.
- 브라우저에서 가장 먼저 실행해야 하는 부분
- index.js는 React, ReactDOM, Menu.js 파일을 import 한다.
- 웹팩은 import 문을 발견할 떄마다 파일시스템에서 해당 모듈을 찾아서 번들에 포함시켜준다.
- 웹팩은 이런 임포트 트리를 쫓아가면서 필요한 모듈을 모두 번들에 넣어준다.
- 이 모든 파일을 순회하면 의존 관계 그래프 (dependency graph)가 생긴다.
import 문
Recipe 앱은 import문을 사용하지만, 노드나 현재 사용중인 대부분의 브라우저는 이를 지원하지 않는다.
그럼에도 불구하고 import문이 작동할 수 있는 이유는 바벨이 import를 require('모듈/경로')로 변환하기 때문이다. require 함수는 일반적으로 커먼JS에서 모듈을 임포트할 때 사용하는 함수이다.
V webpack.config.js
- 모듈화한 조리법 앱이 작동하게 만들려면 소스 코드를 어떻게 한 번들 파일로 만들 수 있는지 웹팩에게 알려줘야 한다.
- 웹팩 버전 4.0부터 설정파일을 만들지 않고 디폴트 방식을 사용할 수 있지만, 설정파일을 사용하면 설정을 원하는대로 커스텀화할 수 있다.
- 디폴트 웹팩 설정 파일은 항상 webpack.config.js 이다.
/* webpack.config.js */
const path = require("path");
module.exports = {
entry : "./src/index.js", // entry point : "./src/index.js"
output : path.join(__dirname, "dist", "assets"), // output : "./dist/assets/bundle.js"
filename : "bundle.js",
}
}
- 웹팩에게 클라이언트의 시작 파일이 ./src/index.js 라는 사실을 지정한다.
- 웹팩은 그 파일안에 있는 import문부터 시작해서 모든 의존 관계 그래프를 자동으로 만든다.
- 번들을 ./dist/bundle.js라는 자바스크립트 파일에 출력하라고 지정한다.
- 웹팩은 이 위치에 패키징한 자바스크립트 파일을 넣어준다.
5-2. babel
V 필요한 바벨 의존 관계를 설치한다.
npm install -D @babel-loader @babel/core
V 웹팩에 사용할 loader를 지정한다.
- 웹팩에 사용할 여러 유형의 로더 목록들을 포함하기 위해, 설정파일에서 module에 내용을 추가한다.
- test : /\.js$/
- 각 모듈에서 로더가 적용해야 하는 파일 경로를 찾기 위한 정규 표현식
- 제외할 모듈을 없애기 위해 exclude 사용 ( ./node_modules/ 하위의 .js 파일 제외) - loader: "babel-loader"
- 바벨을 실행할 때 사용할 presets을 지정한다. 프리셋을 지정하면 바벨에게 어떤 식으로 파일을 변환할지 알려줄 수 있다. ("바벨, 이 프로젝트에서 ESNext 구문을 보면 코드를 브라우저가 이해할 수 있는 구문으로 변환하고 계속 진행해줘.")
5-3. bable:presets 및 번들 생성
V presets 설치한다.
npm install -D @babel/preset-env @babel/preset-react
@babel/preset-env : 자바스크립트의 최신문법을 변환해준다.
@babel/preset-react : 리액트 코드를 변환해준다.
V 프로젝트 루트에 .babelrc 파일을 만들어 아래 코드를 추가한다.
// ./babelrc
{
"presets": ["@babel/preset-env", "@babel/preset-react"]
}
V 번들 생성
개발 서버와 운영 서버에 따라 번들 build 명령을 다르게 할 수 있다.
- 개발 서버
npx webpack --mode development
- 운영 서버
npm run build
npx webpack --mode production
→ 이렇게 하면 ./dist/assets/bundle.js 번들이 생성된다.
6. 실행 (번들 로딩하기)
- 웹팩은 번들을 dist 폴더에 넣는다.
- 이 폴더에는 웹 서버에서 번들을 실행할 때 필요한 파일들이 들어 있다.
- dist 폴더에는 index.html 파일이 포함되어야 한다.
- index.html 파일이 있어야 리액트 Menu 컴포넌트를 마운트시킬 대상 div 엘리먼트를 찾을 수 있고, 방금 만든 번들을 로딩하기 위한 script 태그도 들어 있다.
// ./dist/index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>proj: recipes-app-01</title>
</head>
<body>
<!-- Root element -->
<div id="root"></div>
<script src="assets/bundle.js"></script> // 번들 로딩
</body>
</html>
- 배포 폴더인 assets에 bundle.js 번들을 로딩한다.
7. 소스 맵
코드를 한 번들 파일로 만들면 브라우저에서 앱을 디버깅할 때 우리가 문맥을 이해하기 어려워질 수 있다.
이러한 문제를 소스 맵을 통해 해결할 수 있다.
소스 맵
- 원본 소스와 난독화 된 소스를 매핑
- webpack.config.js 파일에 아래 코드를 추가하면 된다.
- 추가 후 다시 웹팩을 실행하면 assets 폴더에 bundle.js와 bundle.map 두 파일이 생긴다.
// webpack.config.js
...
module.exports = {
...
devtool : '#source-map'
};
자동으로 프로젝트 생성하기
프로젝트 생성 (create-react-app)
create-react-app
- 리액트 프로젝트를 생성하는 도구
- 프로젝트 구조와 패키지별 의존관계 설정
V create-react-app 을 사용하기 위한 패키지 설치 (npm 전역 패키지 필요)
npm install -g create-react-app
V create-react-app 명령과 앱을 생성할 폴더의 이름을 지정하면 앱을 만들 수 있다.
npx create-react-app project_name
V 앱 실행하기
cd project_name // 앱을 생성한 폴더로 이동
npm start // 실행하기
'React' 카테고리의 다른 글
dependencies와 devDependencies (2) | 2024.02.14 |
---|---|
리액트 상태 관리 (0) | 2023.11.05 |
리액트의 작동 원리 (0) | 2023.11.01 |
자바스크립트를 활용한 함수형 프로그래밍 (0) | 2023.10.31 |
React를 위한 자바스크립트2 (0) | 2023.10.30 |