JSX란 중괄호 {} HTML과 차이 하나로 감싸기 주석·예고 📝 문제풀이
◀ 이전 📋 목차 CH 03 ▶
🏷️ CHAPTER 02 · 입문

JSX — HTML처럼 생긴 그 문법의 정체

리액트를 처음 보면 자바스크립트 안에 HTML이 들어가 있어 당황하게 돼요. 그게 바로 JSX예요. 이번 장에서 "이게 뭔지, 왜 이렇게 생겼는지, 진짜 HTML과 뭐가 다른지"를 하나씩 뜯어봐요.

🎯 이 장을 끝내면
🏷️
JSX란
JSX = JavaScript + XML
이름부터 정체를 알려줘요. "자바스크립트 안에 쓰는 XML(HTML 비슷한 것)".

JSX(JavaScript XML)자바스크립트의 확장 문법이에요. 화면에 그릴 모양을 HTML처럼 생긴 태그로 자바스크립트 코드 안에 바로 적을 수 있게 해줍니다. 아래를 보면 "이게 HTML인가 자바스크립트인가?" 싶은데, 둘 다예요 — 자바스크립트인데 HTML 모양을 빌려 쓴 거죠.

const element = <h1>안녕, 리액트!</h1>;
// 변수(element)에 "화면 조각"을 담았어요. 이 <h1>…</h1> 부분이 바로 JSX예요.
🤔 왜 이런 걸 만들었을까? 예전엔 화면을 만들려면 자바스크립트로 document.createElement('h1')처럼 요소를 하나하나 만들고 붙이는 지루한 코드를 써야 했어요. JSX는 그 과정을 우리가 눈으로 보는 HTML 모양 그대로 적게 해줘서, "코드를 보면 결과 화면이 그려지는" 큰 장점이 있어요. JSX는 "필수"는 아니에요. 없이도 리액트를 쓸 수 있지만, 거의 모든 사람이 JSX를 씁니다. 훨씬 읽기 쉬우니까요.

그런데 여기서 아주 중요한 사실 하나. 브라우저는 JSX를 직접 읽지 못해요. <h1>이 자바스크립트 문법에는 없거든요. 그래서 Babel(바벨)이라는 변환기가 JSX를 진짜 자바스크립트 함수 호출로 바꿔줍니다. 아래처럼요.

// 우리가 쓴 JSX
const element = <h1 className="title">안녕</h1>;

// Babel이 변환한 실제 자바스크립트 (개념)
const element = React.createElement(
  "h1",                  // 태그 이름
  { className: "title" },// 속성(props)
  "안녕"                  // 자식(children)
);
🖼️ 그림으로 보기 — JSX가 화면이 되기까지
✍️ 우리가 쓴 JSX <h1>안녕</h1> 🔄 Babel 변환 JSX → 함수 호출 ⚙️ createElement React.createElement(…) 🖥️ 화면 렌더 실제 DOM 생성
💡
한 줄 요약. JSX는 결국 자바스크립트예요. 브라우저가 못 읽어서 Babel이 React.createElement(...) 호출 코드로 변환해주는 것뿐이에요. "HTML을 쓰는 게 아니라, HTML처럼 생긴 자바스크립트를 쓴다"는 감각이 핵심입니다.
JSX JavaScript XML Babel React.createElement 확장 문법 결국 자바스크립트
🧩 JS · JSX · React, 대체 뭐가 다른 거예요? — 헷갈리면 여기 (예시 많음) — 펼쳐 보기
가장 헷갈리는 지점이에요. 핵심은 — 셋은 "이것 아니면 저것"이 아니라 층위가 달라서 함께 쓰여요. 그래서 리액트 코드의 대부분은 그냥 자바스크립트고, "JSX인데 JS 같다"는 느낌이 맞아요.

① 한눈에 — 셋의 정체
구분정체
JavaScript언어(밑바탕)변수·함수·if·.map()·=> — 어디서나 돌아요
JSX문법 확장JS 안에 <button>클릭</button> 같은 태그를 쓰게 해줘요(Babel이 React.createElement로 변환)
React라이브러리(도구)useState·props·컴포넌트·화면 렌더링·onClick 연결
② 한 줄씩 뜯어보기 (섞여 있는 경우)
function App() {                        // ← 그냥 JavaScript (함수)
  function handleClick() {              // ← 그냥 JavaScript
    alert('버튼이 눌렸어요!');           // ← 그냥 JavaScript (브라우저 기능)
  }
  return (
    <button onClick={handleClick}>클릭</button>   // ← 여기서만 섞임
  );
}
마지막 줄 <button onClick={handleClick}>클릭</button> 안에서: <button>…</button> 태그 모양은 JSX, {handleClick}로 JS 값을 꽂는 건 JSX 문법(안의 handleClick은 JS), onClick이 실제 클릭에 연결돼 화면에 그려지는 건 React예요.

③ 예시로 확실히 — 각각 순수하게
· 순수 JS만 (태그 없음 → JSX·React 전혀 없음)
const nums = [1, 2, 3];
const doubled = nums.map(n => n * 2);   // [2,4,6] — 100% 자바스크립트
· JSX가 섞임 (<h1> 태그 등장)
const el = <h1>안녕</h1>;   // const el = 은 JS, <h1>…</h1> 이 JSX
· React 고유 (훅·컴포넌트)
const [n, setN] = useState(0);   // useState = React, [n, setN] 구조분해 = JS
④ 빠른 구별법
  1. <태그>가 보이면 → JSX (그 태그만 지우면 순수 JS예요).
  2. 함수·변수·조건·반복·.map()·=> 같은 로직 → 그냥 JavaScript.
  3. useState·useEffect·props·컴포넌트·렌더링·onClick 연결 → React.

⑤ 자주 하는 오해 — 중괄호 { }는 "리액트"가 아니에요
중괄호는 세 가지로 나뉘는데, 둘은 순수 JS예요:
function f() { ... }              // { } = 자바스크립트 (함수 몸통)
const p = { name: '철수' };       // { } = 자바스크립트 (객체)

<h1>{name}</h1>                   // { } = JSX 문법 (JSX 안에 JS 값 넣기)
<button onClick={handleClick}>   // { } = JSX 문법
JSX 안(태그 사이·속성)의 { }는 "여기 JS 값을 넣어라"는 JSX 문법이고, 그냥 코드의 { }(함수 몸통·객체)는 그냥 JS예요. 어느 쪽도 리액트는 아니에요.

그럼 리액트는 중괄호가 아니라 "이름"으로 알아봐요:
const [n, setN] = useState(0);        // use로 시작하는 훅 → React
useEffect(() => { ... }, []);         // 훅 → React
function App() { return <div/> }      // 대문자 컴포넌트 + JSX 반환 → React
<Button label="확인" />               // 대문자 태그(내 컴포넌트) + props → React
즉 리액트를 알아보는 표시는 use~로 시작하는 훅, ②대문자로 시작하는 컴포넌트, ③props — 중괄호랑은 상관없어요.

🍳 비유: JS = 재료와 조리법(언어), React = 주방 도구 세트(라이브러리), JSX = 요리를 예쁘게 담는 그릇 모양 문법. 도구를 써도 결국 요리(로직)는 자바스크립트로 해요.
👉 정리: 리액트 = 자바스크립트 + JSX 문법 + 라이브러리. 대부분은 그냥 JS예요. 그래서 "자바스크립트를 잘해야 리액트를 잘한다"는 말이 나오는 거예요 — 리액트가 JS를 대체하는 게 아니라 그 위에 얹히는 거니까요.
▲ 접기
🧮
중괄호 {}
JSX 안에서 자바스크립트 쓰기
태그 안에 { }를 열면, 그 안은 다시 자바스크립트 세상이에요.

JSX는 HTML 모양이지만, 중간에 중괄호 { }를 열면 그 안에서 자바스크립트 값을 꺼내 쓸 수 있어요. 변수, 계산식, 객체 속성, 함수 호출 결과 등 "값이 되는 것"이면 무엇이든 들어갈 수 있어요.

const name = "지훈";
const user = { age: 20 };

const element = (
  <div>
    <p>안녕, {name}!</p>         {/* 변수 */}
    <p>1 + 2 = {1 + 2}</p>       {/* 계산식 */}
    <p>나이: {user.age}살</p>     {/* 객체 속성 */}
    <p>대문자: {name.toUpperCase()}</p>  {/* 함수 호출 결과 */}
  </div>
);
🧠 먼저 — 코드엔 딱 두 종류가 있어요 (용어 빼고) 🟦 순수 JS 컴퓨터가 보는 코드는 크게 둘로 나뉘어요.

① 계산하면 "값 하나"가 되는 코드 — 실행하면 결과값 하나가 딱 나와요.
  1010,   1 + 2 → 계산하면 3,   "안녕"안녕.
  그럼 변수 name 은요? 이렇게 생각하면 쉬워요:
  const name = "지훈"; 이라고 정해두면, 코드 속 name 은 컴퓨터가 속으로 "지훈" 으로 바꿔서 봐요. 즉 name 도 결국 값 하나("지훈")가 되는 거예요.
이렇게 계산하면 값 하나가 되는 코드식(Expression)이라 불러요.

② 그냥 "시키기만" 하는 코드 — 계산해도 값이 안 나와요.
  if (x > 0) { ... } → "조건 보고 필요하면 실행해"라는 명령일 뿐(값 없음).
  let a = 10; → "a라는 변수를 만들어"라는 명령(값 없음).
이렇게 시키기만 하는 코드문(Statement)이라 불러요. 💡 구분법은 딱 하나예요: "계산했을 때 값 하나가 나오면 식, 그냥 시키기만 하면 문."
🙋
"어? if (10 > 5) { "YES" } 안엔 "YES"가 있잖아요?" — 좋은 질문! 하지만 여기서 "YES"if의 결과값으로 쓰이는 게 아니라, 그냥 안에 적힌 코드 한 줄일 뿐이에요. if문 자체는 값을 만들어 내는 문법이 아니거든요. 그래서 const b = if (...) 처럼 값 자리에 쓰면 에러가 나요.
⚠️ 그래서 JSX 중괄호 { } 안엔 "식"만 돼요 🟪 리액트 중괄호 안은 "최종적으로 무엇이 화면에 들어갈까?"를 계산하는 자리예요. 그래서 계산하면 값이 되는 "식"만 들어갈 수 있어요.

예를 들어 <h1>{1 + 2}</h1> 를 보면 리액트는 속으로 이렇게 처리해요:
  화면에 넣을 값 = 1 + 2  →  화면에 넣을 값 = 3  →  <h1>3</h1>
마찬가지로 <h1>{name}</h1>name"지훈"이 되니까 <h1>지훈</h1> 이 돼요. ✅

그런데 <h1>{ if (x>0){...} }</h1> 는? "화면에 넣을 값 = ???" — if값을 만들지 않으니 채울 게 없어요. → 그래서 안 돼요. ❌ 🍽️ 비유: 중괄호는 "접시에 담을 완성된 요리(값)"를 놓는 자리예요. "요리를 하라"는 명령(문)은 접시에 담을 수 없죠.
넣을 수 있는 것 (식)넣을 수 없는 것 (문)
{name} 변수{if (x) {...}} if 문 ❌
{1 + 2} 계산식{for (...) {...}} for 문 ❌
{cond ? 'A' : 'B'} 삼항 연산{let a = 1} 변수 선언 ❌
{isOk && <p>OK</p>} 논리곱{switch(...)} switch 문 ❌
{list.map(...)} 배열 메서드 
💡
그럼 조건 분기는 어떻게? if문 대신 삼항 연산자 조건 ? A : B&&를, 반복은 .map()을 써요. 이들은 전부 "계산하면 값이 되는 식"이라 중괄호 안에 들어갈 수 있어요. (자세한 활용은 뒤 챕터에서!)
🔀
HTML과 차이
HTML과 살짝 다른 다섯 가지
JSX는 HTML "처럼" 생겼을 뿐, 자바스크립트라서 규칙이 조금 달라요.

JSX는 결국 자바스크립트예요. 그래서 자바스크립트에서 이미 예약된 단어와 겹치거나, 문법 규칙에 맞춰 HTML과 다르게 써야 하는 것들이 있어요. 대표적인 다섯 가지를 봅시다.

① class → className 🟪 리액트 HTML의 class는 자바스크립트에서 이미 예약어(class 문법)라서 그대로 못 써요. 그래서 CSS 클래스를 줄 땐 className을 씁니다.
// HTML:  <div class="box">
// JSX:
const el = <div className="box">내용</div>;
🧩 그런데 HTML의 class가 대체 뭐예요? — 펼쳐 보기
먼저 알아둘 점 — 여기서 말하는 class프로그래밍의 "클래스(class)" 개념이 아니라, HTML의 속성(attribute)이에요. 이름만 같고 완전히 다른 거예요.

1) HTML 뜯어보기
<div class="box">내용</div> 를 조각내면:
  • div태그
  • class="box"속성(attribute)
  • 내용 → 태그 안의 내용
<div class="box">"이 div에 box라는 이름표를 붙여라"라는 뜻이에요.

2) 왜 이름표를 붙일까?
CSS가 이 이름표를 보고 꾸며주기 때문이에요. 예를 들어 CSS에 이렇게 쓰면:
.box { color: red; font-size: 30px; }
브라우저는 "아, box 이름표가 붙은 요소네?" 하고 그 글자를 빨간색·30px로 꾸며줘요. 그러니까 class"이 요소가 어떤 그룹인지 알려주는 이름표"인 셈이죠.

3) 비유 — 교실의 축구부 이름표
교실에 철수·영희·민수가 있는데, 축구부 학생에게만 체육복을 입히고 싶어요. 그래서 축구부 학생에게 축구부라는 표시를 붙이죠. HTML도 똑같아요 — <div class="soccer"> 라고 붙이면 CSS .soccer { color: blue; } 가 그 그룹만 골라 꾸며줘요.

4) 그럼 React에선 왜 class를 못 쓸까?
JSX는 HTML 파일이 아니라 자바스크립트 코드 안에서 쓰여요. 그런데 자바스크립트엔 이미 class Person {} 처럼 class라는 문법이 존재해요. 이름이 겹쳐 충돌하니까, React는 대신 className을 쓰는 거예요. 둘은 완전히 같은 역할이에요.

5) 그럼 브라우저엔 뭐가 전달될까?
우리가 <div className="box"> 라고 쓰면, React가 최종적으로 브라우저에는 <div class="box"> 를 만들어 줘요. 즉 작성할 때는 className, 브라우저가 받는 HTML은 class 예요.

👉 한 문장 정리: HTML의 class는 "CSS가 이 요소를 찾도록 붙이는 이름표(속성)"이고, JSX에선 자바스크립트의 class 문법과 겹쳐서 className을 쓴다.
▲ 접기
② for → htmlFor 🟪 리액트 <label for="...">for 역시 자바스크립트의 for 반복문과 겹쳐서, JSX에선 htmlFor로 씁니다.
// HTML:  <label for="email">
// JSX:
const el = <label htmlFor="email">이메일</label>;
③ 이벤트는 카멜케이스 (onclick → onClick) 🟪 리액트 HTML은 onclick처럼 전부 소문자지만, JSX는 카멜케이스(camelCase)onClick, onChange, onMouseOver처럼 써요. 그리고 값으로 함수(문자열이 아니라!)를 넘겨요.
// HTML:  <button onclick="doSomething()">
// JSX:
const el = <button onClick={handleClick}>클릭</button>;
// 속성값이 문자열 "..."이 아니라, 중괄호 안의 함수라는 점에 주목!
④ 모든 태그는 반드시 닫기 (self-closing) 🟪 리액트 HTML은 <img>, <br>, <input>처럼 닫지 않아도 됐지만, JSX(XML 규칙)에선 모든 태그를 닫아야 해요. 자식이 없는 태그는 스스로 닫는 형태 />로 마무리합니다.
// HTML:  <img src="a.png">   <br>   <input type="text">
// JSX (반드시 닫기):
const el = (
  <div>
    <img src="a.png" />
    <br />
    <input type="text" />
  </div>
);
⑤ style은 문자열이 아니라 "객체" 🟪 리액트 HTML은 style="color:red"처럼 문자열을 줬지만, JSX는 자바스크립트 객체를 줘요. 그래서 중괄호가 두 겹이에요 — 바깥 { }는 "JSX 안에서 JS를 연다", 안쪽 { }는 "객체"예요. 속성 이름도 background-color 대신 카멜케이스 backgroundColor를 씁니다.
// HTML:  <div style="color:red; background-color:yellow">
// JSX (객체로!):
const el = <div style={{ color: 'red', backgroundColor: 'yellow' }}>내용</div>;
//                      ▲바깥 {}=JS   ▲안쪽 {}=객체
HTMLJSX이유
classclassNameclass는 JS 예약어
forhtmlForfor는 JS 반복문 키워드
onclickonClickJSX는 카멜케이스 이벤트
<br><br />모든 태그는 닫아야 함
style="..."style={{...}}문자열이 아니라 객체
⚠️
자주 하는 실수. class="box"라고 쓰면 리액트가 콘솔에서 경고를 띄우고 CSS가 안 먹을 수 있어요. HTML 습관 때문에 나오는 실수 1위가 바로 이거예요. className을 기억하세요!
🎁
하나로 감싸기
JSX는 최상위가 "하나"여야 해요
여러 태그를 반환하려면 하나의 부모로 묶어야 합니다.

JSX 한 덩어리는 최상위 요소가 반드시 하나여야 해요. 아래처럼 나란히 두 개를 반환하면 에러가 납니다.

// ❌ 에러! 최상위가 <h1>과 <p> 두 개
const el = (
  <h1>제목</h1>
  <p>본문</p>
);
🤔 왜 하나여야 할까? 🟪 리액트 JSX는 결국 React.createElement(...) 하나의 값으로 변환돼요. 함수가 값을 돌려줄 때 return하나만 돌려줄 수 있죠. 마치 상자에 물건을 담아 건네줄 때 상자 하나로 묶어야 하는 것과 같아요. 그래서 여러 요소를 부모 하나로 감싸야 합니다.
🧩 "최상위는 하나" 개념 자세히 — "함수는 값을 하나만 반환한다"부터 차근차근 — 펼쳐 보기
위 박스의 React.createElement 얘기는 사실 지금 단계에선 오히려 헷갈려요. 아직 createElement가 뭔지 안 배웠으니까요. 그것 없이도 이해할 수 있는 훨씬 쉬운 출발점이 있어요: "함수는 값을 하나만 반환(return)한다."

1) 먼저 그냥 함수부터
평범한 자바스크립트 함수를 볼게요.
function test() {
  return 10;
}
// 이 함수의 결과 → 10
return "안녕" 이면 결과는 안녕 이에요. 여기까진 쉽죠.

2) return을 두 번 쓰면?
function test() {
  return 10;
  return 20;   // 이 줄은 실행조차 안 돼요
}
결과가 1020 둘 다일까요? 아니에요. 함수는 첫 번째 return을 만나는 순간 그 자리에서 끝나요. 그래서 10 하나만 돌려줘요. 이게 핵심이에요 — 함수가 돌려주는 값은 언제나 딱 하나.

3) 리액트 컴포넌트도 결국 "함수"예요
function App() {
  return (
    <h1>안녕하세요</h1>
  );
}   // ✅ <h1> 하나를 반환 → OK
그런데 이렇게 형제 둘을 나란히 두면?
function App() {
  return (
    <h1>제목</h1>
    <p>본문</p>
  );
}   // ❌ 에러
리액트 입장에선 이래요: "잠깐, 뭘 반환하라는 거야? <h1>? <p>? 둘 다?" 함수는 값을 하나만 줄 수 있는데 형제가 이라 애매해진 거예요.

4) 그래서 "상자 하나"로 묶어요
function App() {
  return (
    <div>
      <h1>제목</h1>
      <p>본문</p>
    </div>
  );
}
이제 반환되는 건 <div> 딱 하나예요. 그 안에 h1p가 들어있는 거죠.

📦 택배 비유
택배로 사과와 바나나를 그냥 두 개 던져주면 기사님이 "어느 걸 보내라는 거죠?" 하고 물어요. 그래서 상자 하나에 담죠:
📦 상자 ├── 🍎 사과 └── 🍌 바나나
그러면 배송되는 건 📦 상자 하나. JSX도 똑같아요.

🌳 나무(Tree)로 보면
<div>로 감싸면 리액트가 보는 건 뿌리 하나짜리 나무 하나예요:
div ← 뿌리 하나 ├── h1 └── p
그런데 <h1><p>를 그냥 나란히 두면 나무가 둘이 돼서, 리액트가 "어느 나무를 반환해야 하지?" 하고 막혀요.

👉 한 문장 정리: 컴포넌트는 함수고, 함수는 값을 하나만 반환할 수 있어요. 그래서 JSX도 최상위를 하나로 묶어야 해요. (위 박스의 "createElement 하나의 값"도 결국 같은 뜻 — 그건 뒤 챕터에서 자연스럽게 이어져요.)
"최상위를 하나로 묶어야 한다." = "JSX는 여러 요소를 하나의 부모 요소로 감싸야 한다." 와도 같은 뜻이에요.

"JSX 에서는 최상위는 <div>로 묶는 경우 <div>는 하나다."
최상위를 하나로 묶어야 한다.
        ↓
부모 요소가 하나여야 한다.
        ↓
보통은 <div> 하나로 감싼다.
(또는 Fragment, section, main 등을 사용할 수도 있다.)
<div>일 필요는 없어요. 아래 해결 방법 2 — Fragment <>…</>는 화면에 태그를 하나도 안 남기면서 묶어주는 "투명한 상자"예요.
<section>
  <h1>제목</h1>
  <p>내용</p>
</section>
<main>
  <h1>제목</h1>
  <p>내용</p>
</main>
<>
  <h1>제목</h1>
  <p>내용</p>
</>
즉, 부모 요소가 하나만 있으면 된다.
📦 <>...</>(Fragment) 를 사용하는 경우 — 펼쳐 보기
React를 배우다 보면 오히려 불필요한 <div>를 만들지 않기 위해 <>...</>(Fragment)를 많이 사용하는 경우도 많습니다.

왜 Fragment를 쓰게 되나
React 컴포넌트JSX를 하나의 최상위 요소로 감싸서 반환해야 하는 규칙이 있습니다.
function Profile() {
  return (
    <h2>이름</h2>
    <p>소개</p>
  ); // ❌ 에러! 최상위 요소가 2개
}
이걸 해결하려고 예전에는 흔히 `<div>`로 감쌌습니다.
문제는 이 <div>가 "의미 없이 껍데기만 추가"한다는 것
<div>는 레이아웃상 필요해서 넣은 게 아니라, 그냥 React 문법 규칙을 맞추려고 억지로 넣은 것뿐이에요. 그런데 이게 쌓이면:

실제 HTML 결과물에 불필요한 <div>가 계속 중첩됩니다.
특히 테이블(<table>) 안에서 컴포넌트를 쓸 때, 엉뚱한 <div><tr>/<td> 사이에 끼어들면 HTML 구조 자체가 깨지는 문제가 생기기도 합니다.
CSSflexgrid 레이아웃을 짤 때도, 이 의미 없는 <div> 때문에 자식 요소 간격이나 정렬이 예상과 다르게 나올 수 있습니다.

그래서 등장한 게 Fragment
function Profile() {
  return (
    <>
      <h2>이름</h2>
      <p>소개</p>
    </>
  ); // ✅ 실제 HTML엔 <div> 없이 <h2>, <p>만 남음
}
<>...</>"여러 요소를 묶긴 하는데, 실제 화면에는 아무 태그도 남기지 마"라는 뜻입니다. React 문법(최상위 요소 1개)은 만족시키면서, 결과물 HTML에는 껍데기가 안 남는 거예요.

정리
방식실제 HTML에 남는 것
<div>로 감싸기<div><h2>...</h2><p>...</p></div>
<>...</>(Fragment)<h2>...</h2><p>...</p> (div 없음)
▲ 접기
▲ 접기

해결 방법 1 — <div>로 감싸기. 가장 쉬운 방법이에요.

// ✅ div 하나로 감싸기
const el = (
  <div>
    <h1>제목</h1>
    <p>본문</p>
  </div>
);

해결 방법 2 — Fragment <>…</>. <div>로 감싸면 실제 화면에 불필요한 태그가 하나 더 생겨요. 그게 싫을 때, 화면에 아무 태그도 남기지 않고 묶어주는 Fragment(프래그먼트)를 씁니다. 빈 태그 <></> 모양이에요.

// ✅ Fragment로 감싸기 (실제 DOM에 여분의 태그가 안 생겨요)
const el = (
  <>
    <h1>제목</h1>
    <p>본문</p>
  </>
);
// <>…</> 는 <React.Fragment>…</React.Fragment> 의 짧은 형태예요.
💡
언제 무엇을? 감싸는 <div>className이나 style이 필요하면 <div>를, 순전히 "묶기"만 필요하고 여분의 태그를 남기고 싶지 않으면 Fragment <></>를 쓰면 돼요.
💬
주석·예고
JSX 주석, 그리고 앞으로 나올 것들
마지막으로 소소하지만 자주 쓰는 것 하나와 예고편이에요.

JSX 태그 안쪽에 주석을 달 때는 {/* … */} 형태를 써요. 중괄호로 자바스크립트 세상을 열고, 그 안에 자바스크립트 주석 /* */을 넣는 구조예요. HTML 주석 <!-- -->은 JSX 안에서 그대로 쓰면 안 됩니다.

const el = (
  <div>
    {/* 이건 JSX 안의 주석이에요 */}
    <h1>안녕</h1>
    {/* 여러 줄
        주석도 가능 */}
  </div>
);
🔜 다음 챕터 예고 이번 장에서 살짝 언급한 조건부 렌더링(삼항·&&)리스트 렌더링(.map())은 실전에서 아주 많이 쓰여요. 이건 뒤 챕터에서 예제와 함께 제대로 다룹니다. 지금은 "중괄호 안엔 식만, if·for는 못 쓴다"는 원리만 확실히 챙기면 충분해요. 다음 CH 03에서는 JSX 덩어리를 재사용 가능한 부품(컴포넌트)으로 만들고, 데이터를 props로 넘기는 법을 배워요.
🧭
여기까지 감각 점검. "JSX = HTML처럼 생긴 JS → Babel이 createElement로 변환 → 중괄호엔 식만 → HTML과 다른 규칙 몇 가지 → 하나로 감싸기." 이 흐름이 머릿속에 그려지면 이번 장은 통과예요. 아래 문제로 확인해봐요.
🧠 이 장 핵심 요약
📝
문제풀이 · 점검
배운 걸 가볍게 점검해봐요
시험이 아니라 "내가 이해했나" 확인용이에요. 틀려도 바로 해설이 나와요.
🧪
문제를 풀면 즉시 정답과 해설이 나오고, 위쪽 바에 점수가 쌓여요. 네 가지 유형(객관식 · O/X · 빈칸 · 코드)을 섞어 두었어요.
CH 03 🧩 컴포넌트와 props — JSX 덩어리를 재사용 가능한 부품으로