Notice
Recent Posts
Recent Comments
Link
«   2025/03   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31
Archives
Today
Total
관리 메뉴

성빈

JSX를 사용하는 리액트 본문

React

JSX를 사용하는 리액트

성빈나 2023. 11. 3. 23:47

목차

  • 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 활용

  1. JavaScript 최신 문법의 활용과 호환성
    (최신 문법을 지원하지 않는 하위 브라우저를 위한 하위 호환성)
  2. 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