JSX 문법 이해하기
1장 마지막에서 잠시 언급했듯이, 리액트 컴포넌트를 작성할 때 우리는 HTML과 매우 유사하게 생긴 특별한 문법을 사용했습니다. 바로 JSX(JavaScript XML)입니다.
이번 장에서는 리액트 개발의 핵심이자 필수적인 JSX 문법에 대해 깊이 있게 알아보는 시간을 갖겠습니다. JSX는 처음 볼 때는 낯설게 느껴질 수 있지만, 익숙해지면 리액트 컴포넌트를 매우 직관적이고 효율적으로 작성할 수 있도록 돕는 강력한 도구입니다.
JSX란 무엇인가?
JSX는 JavaScript XML의 약자로, 이름에서 알 수 있듯이 자바스크립트 코드 내부에 XML/HTML과 유사한 구문을 작성할 수 있게 해주는 문법 확장입니다. 리액트에서 UI를 정의할 때 사용되며, 내부적으로는 자바스크립트 객체로 변환됩니다.
JSX의 특징- HTML처럼 보이지만 자바스크립트입니다. JSX는 겉보기에는 HTML 태그처럼 보이지만, 실제로는 자바스크립트 코드의 일부입니다. 덕분에 자바스크립트의 모든 기능을 JSX 내부에서 활용할 수 있습니다.
- 컴파일 과정: 웹 브라우저는 JSX를 직접 이해하지 못합니다. 따라서 JSX 코드는 바벨(Babel)과 같은 트랜스파일러(Transpiler)에 의해 일반 자바스크립트 코드로 변환된 후 브라우저에서 실행됩니다. Vite 기반 프로젝트에서는 이 변환 과정이 기본 개발 서버/빌드 파이프라인에 포함되어 있습니다.
- UI를 선언적으로 표현: JSX는 무엇을 보여줄 것인가를 직관적으로 선언할 수 있게 하여 UI 구조를 한눈에 파악하기 용이하게 만듭니다.
JSX의 기본 규칙
JSX는 HTML과 유사하지만 몇 가지 중요한 규칙을 따릅니다. 이 규칙들을 정확히 이해하는 것이 중요합니다.
항상 하나의 루트(Root) 요소 반환
리액트 컴포넌트는 JSX를 반환할 때, 반드시 하나의 최상위(Root) 요소로 감싸져야 합니다. 두 개 이상의 요소가 나란히 존재할 수 없습니다.
// ⭕ 올바른 예시: 하나의 div로 감싸져 있음
function MyComponent() {
return (
<div>
<h1>안녕하세요!</h1>
<p>리액트를 배워봅시다.</p>
</div>
);
}
// ❌ 잘못된 예시: 두 개의 최상위 요소
// function MyComponent() {
// return (
// <h1>안녕하세요!</h1>
// <p>리액트를 배워봅시다.</p>
// );
// }만약 불필요한 <div> 태그를 추가하고 싶지 않다면, 프래그먼트(Fragment)를 사용할 수 있습니다. 프래그먼트는 <></> 또는 <React.Fragment></React.Fragment>와 같이 작성하며, 실제 DOM에는 렌더링되지 않는 유령 같은 요소입니다.
// ⭕ 올바른 예시: 프래그먼트 사용
import React from 'react'; // React.Fragment를 사용하려면 React를 임포트해야 합니다.
function MyComponent() {
return (
<> {/* 단축 문법: <React.Fragment>와 동일 */}
<h1>안녕하세요!</h1>
<p>리액트를 배워봅시다.</p>
</>
);
}
// 또는 명시적으로
function MyComponentWithFragment() {
return (
<React.Fragment>
<h1>안녕하세요!</h1>
<p>리액트를 배워봅시다.</p>
</React.Fragment>
);
}프래그먼트는 특히 여러 컴포넌트를 묶어 반환하거나, 리스트를 렌더링할 때 유용하게 사용됩니다.
HTML 속성 이름의 CamelCase 규칙
JSX에서는 HTML 속성(Attribute) 이름을 작성할 때 자바스크립트의 CamelCase(카멜 케이스) 규칙을 따릅니다. 이는 자바스크립트에서 DOM 속성을 다룰 때도 유사한 규칙을 따르기 때문입니다.
class->classNamefor->htmlFortabindex->tabIndexonclick->onClick
function MyButton() {
return (
<button className="my-button" onClick={() => console.log('클릭!')}>
클릭해주세요
</button>
);
}
// HTML에서는 다음과 같았겠죠?
// <button class="my-button" onclick="console.log('클릭!')">
// 클릭해주세요
// </button>자식 요소가 없는 태그는 항상 닫기
HTML에서는 <img>, <input>, <br>과 같이 자식 요소가 없는 태그를 단일 태그로 작성할 수 있었습니다. JSX에서는 이러한 태그를 사용할 때 항상 스스로 닫는(Self-closing) 형태로 작성해야 합니다.
// ⭕ 올바른 예시
<img src="logo.png" alt="로고" />
<input type="text" />
<br />
// ❌ 잘못된 예시
// <img src="logo.png" alt="로고">
// <input type="text">
// <br>자식 요소가 있는 태그는 HTML과 동일하게 시작 태그와 종료 태그를 사용합니다.
<div>
<p>이것은 단락입니다.</p>
</div>자바스크립트 표현식 삽입: {} 중괄호
JSX 내부에 자바스크립트 변수, 함수 호출 결과, 또는 다른 자바스크립트 표현식을 삽입하고 싶다면 중괄호 {}를 사용합니다.
function Greeting() {
const name = '김코딩';
const age = 30;
const isStudent = true;
function formatGreeting(userName) {
return `안녕하세요, ${userName}님!`;
}
return (
<div>
<h1>{formatGreeting(name)}</h1> {/* 함수 호출 결과 삽입 */}
<p>나이: {age}</p> {/* 변수 값 삽입 */}
{isStudent ? (
<p>저는 학생입니다.</p>
) : (
<p>저는 직장인입니다.</p>
)} {/* 조건부 렌더링 (삼항 연산자) */}
<p>현재 날짜: {new Date().toLocaleDateString()}</p> {/* 자바스크립트 객체 및 메서드 호출 */}
</div>
);
}{변수명}: 변수의 값을 렌더링합니다.{함수명()}: 함수의 반환값을 렌더링합니다.{조건 ? 참일 때 : 거짓일 때}: 삼항 연산자를 사용하여 조건부 렌더링을 할 수 있습니다.- JSX 내에서
if문이나for문과 같은 제어문은 직접 사용할 수 없습니다. 대신 삼항 연산자나 논리 연산자(&&,||), 배열의map()메서드 등을 사용하여 조건을 처리하거나 반복적인 요소를 렌더링합니다. 이 부분은 뒤에서 더 자세히 다루겠습니다.
JSX 내부의 주석
JSX 내부에서 주석을 작성할 때는 자바스크립트 주석 문법과 약간 다릅니다. 중괄호 {} 안에 자바스크립트 주석을 작성해야 합니다.
function CommentExample() {
return (
<div>
{/* 이것은 JSX 내부의 주석입니다 */}
<h1>JSX 주석 예시</h1>
{
// 여러 줄 주석도 가능합니다.
// 이 주석은 화면에 렌더링되지 않습니다.
}
<p>주석은 코드를 설명하는 데 유용합니다.</p>
</div>
);
}JSX의 활용 예시
간단한 예제를 통해 JSX의 활용법을 다시 한번 살펴보겠습니다.
import React from 'react';
function ProductCard(props) {
const { name, price, imageUrl, isInStock } = props; // props를 비구조화 할당
return (
<div className="product-card">
<img src={imageUrl} alt={name} className="product-image" />
<h2>{name}</h2>
<p>가격: {price}원</p>
{isInStock ? ( // 조건부 렌더링
<p style={{ color: 'green', fontWeight: 'bold' }}>재고 있음</p>
) : (
<p style={{ color: 'red' }}>재고 없음</p>
)}
<button onClick={() => alert(`${name}을(를) 장바구니에 담았습니다!`)}>
장바구니 담기
</button>
</div>
);
}
export default ProductCard;위 ProductCard 컴포넌트는 name, price, imageUrl, isInStock과 같은 데이터를 props로 받아 JSX를 통해 동적으로 UI를 구성하고 있습니다.
className="product-card":class대신className을 사용했습니다.src={imageUrl}: 이미지src속성에 자바스크립트 변수imageUrl을 삽입했습니다.onClick={() => ...}:onClick이벤트 핸들러에 자바스크립트 함수를 직접 전달했습니다.style={{ color: 'green', fontWeight: 'bold' }}:style속성에 자바스크립트 객체 형태로 CSS 속성을 직접 부여했습니다. (CSS 속성 이름도 카멜 케이스를 사용합니다. 예:font-weight->fontWeight)
JSX는 리액트 컴포넌트를 작성하는 데 있어 필수적인 문법입니다. 처음에는 규칙들이 낯설게 느껴질 수 있지만, 실제로 코드를 작성하면서 익숙해지는 것이 가장 좋습니다. 다음 절부터는 이 JSX를 활용하여 실제로 컴포넌트를 만들고, 데이터를 전달하고, 이벤트를 처리하는 방법에 대해 본격적으로 다루게 될 것입니다.
JSX 문법 이해하기 장은 여기까지입니다. JSX의 핵심 규칙들과 활용법을 명확하게 전달하고자 노력했습니다. 특히 카멜 케이스 규칙과 단일 루트 요소 반환, 그리고 중괄호를 이용한 자바스크립트 표현식 삽입에 대한 설명을 강조했습니다.
다음 절에서는 JSX를 기반으로 UI를 재사용 가능한 단위로 분리하는 컴포넌트의 개념과 종류를 본격적으로 다룹니다.