JSX 문법
JSX의 단일 루트·속성 이름·태그 닫기 규칙을 익히고 중괄호로 JavaScript 표현식을 UI에 삽입합니다.
1장의 마지막 글에서 잠시 살펴봤듯이, React 컴포넌트를 작성할 때는 HTML과 매우 비슷하게 생긴 JSX(JavaScript XML)라는 문법을 씁니다. 이 글에서는 첫 번째 React 앱 만들기에서 실행한 프로젝트를 바탕으로, 태그를 묶는 구조와 그 안에서 계산하는 값을 나눠 읽는 방법을 익힙니다. JSX는 React에서 널리 쓰는 작성 방식일 뿐이며, React element를 만드는 다른 자바스크립트 API도 있습니다. 익숙해지면 JSX는 컴포넌트의 UI 구조를 직관적으로 작성하는 데 큰 도움이 됩니다.
JSX에서 element 트리까지 — 상태 추적
변환 시 소스와 JavaScript, 실행 시 현재 입력과 element 값은 시점과 값이 다르다. JSX/현재 입력/UI 설명을 고정 역할로 보강하되 element를 DOM으로 표시하지 않는다.
JSX: TRANSFORM & EXECUTE
JSX는 JS 코드로 변환되고 실행될 때 현재 값을 읽습니다
태그를 작성하는 시점과 name·price 같은 값이 평가되는 시점을 구분합니다. React element는 화면의 구조를 기술하는 값이며, 이후 React가 렌더 결과를 DOM에 반영합니다.
1. 소스 작성과 변환
<h2>{name}</h2>
<p>가격: {price}원</p>두 태그는 부모 요소나 Fragment 안에 작성합니다. 도구가 JSX를 JS 호출로 바꾸며, 사용한 JSX runtime 설정에 따라 호출 형태는 달라집니다.
2. 실행 시 현재 props 평가
name: "키보드"
price: 30000
→ 제목 "키보드", 가격 30000원ProductCard가 호출되면 name과 price를 읽고 현재 UI를 기술하는 React element 트리를 반환합니다.
문법 점검: 구조와 태그
인접 JSX는 묶고 태그는 닫습니다. Fragment는 추가 DOM 노드를 만들지 않습니다.
문법 점검: 속성과 표현식
className·htmlFor·onClick을 사용하고, 중괄호 안에는 JS 표현식을 넣습니다. aria-*·data-* 속성은 하이픈을 유지합니다.
이 예의 조건
- 원도표의 전체 구조와 설명은 위 관계도와 표에서 유지합니다. 아래 인쇄 표에도 원도표의 관계·조건·라벨·설명·주석을 보존합니다.
- 두 관찰 칸의 위치는 고정입니다. 관찰 상태는 해당 순간의 값이며, 동작·이유는 그 조건에서의 판정과 변화 원인입니다. 독립 비교와 실패 분기는 별도 조건으로 읽고 모든 분기를 한 요청의 필수 실행 순서로 이어 읽지 않습니다.
관계도의 보충 설명
| 구분 | 내용 |
|---|---|
| 전체 관계·조건 설명 | JSX 소스→JavaScript 변환→현재 입력으로 컴포넌트 실행→React element의 노드 4개·간선 3개다. 도구의 변환과 렌더 계산의 실행 시점이 다르며 element는 DOM 노드 자체가 아니다. |
| 전체 관계·조건 설명 | JSX 소스→JavaScript 변환→현재 입력으로 컴포넌트 실행→React element의 노드 4개·간선 3개다. 도구의 변환과 렌더 계산의 실행 시점이 다르며 element는 DOM 노드 자체가 아니다. 모바일에서도 노드와 연결 방향·독립 경로가 같다. |
| 장면 | 현재 관찰값 | 설명 | 변화 이유 |
|---|---|---|---|
| JSX 작성 | source: JSX / 현재 값: 아직 실행 전 | 태그/props/표현식이 변환 입력에 있다 | JSX는 실제 HTML 문자열을 바로 표시하는 것이 아니다 |
| JavaScript 변환 | 산출: React element 생성 코드 / DOM: 아직 없음 | 도구가 실행 가능한 JS로 변환한다 | 변환 시점과 컴포넌트 입력 평가 시점은 다르다 |
| 현재 입력 평가 | 입력: 현재 props/state / 결과: element 값 | 컴포넌트가 현재 값을 읽어 element UI 설명을 반환한다 | element는 DOM 노드 자체가 아니며 commit은 별도다 |
JSX에서 element 트리까지 — 상태 추적
변환 시 소스와 JavaScript, 실행 시 현재 입력과 element 값은 시점과 값이 다르다. JSX/현재 입력/UI 설명을 고정 역할로 보강하되 element를 DOM으로 표시하지 않는다.
JSX: TRANSFORM & EXECUTE
JSX는 JS 코드로 변환되고 실행될 때 현재 값을 읽습니다
태그를 작성하는 시점과 name·price 같은 값이 평가되는 시점을 구분합니다. React element는 화면의 구조를 기술하는 값이며, 이후 React가 렌더 결과를 DOM에 반영합니다.
1. 소스 작성과 변환
<h2>{name}</h2>
<p>가격: {price}원</p>두 태그는 부모 요소나 Fragment 안에 작성합니다. 도구가 JSX를 JS 호출로 바꾸며, 사용한 JSX runtime 설정에 따라 호출 형태는 달라집니다.
2. 실행 시 현재 props 평가
name: "키보드"
price: 30000
→ 제목 "키보드", 가격 30000원ProductCard가 호출되면 name과 price를 읽고 현재 UI를 기술하는 React element 트리를 반환합니다.
문법 점검: 구조와 태그
인접 JSX는 묶고 태그는 닫습니다. Fragment는 추가 DOM 노드를 만들지 않습니다.
문법 점검: 속성과 표현식
className·htmlFor·onClick을 사용하고, 중괄호 안에는 JS 표현식을 넣습니다. aria-*·data-* 속성은 하이픈을 유지합니다.
이 예의 조건
- 원도표의 전체 구조와 설명은 위 관계도와 표에서 유지합니다. 아래 인쇄 표에도 원도표의 관계·조건·라벨·설명·주석을 보존합니다.
- 두 관찰 칸의 위치는 고정입니다. 관찰 상태는 해당 순간의 값이며, 동작·이유는 그 조건에서의 판정과 변화 원인입니다. 독립 비교와 실패 분기는 별도 조건으로 읽고 모든 분기를 한 요청의 필수 실행 순서로 이어 읽지 않습니다.
관계도의 보충 설명
| 구분 | 내용 |
|---|---|
| 전체 관계·조건 설명 | JSX 소스→JavaScript 변환→현재 입력으로 컴포넌트 실행→React element의 노드 4개·간선 3개다. 도구의 변환과 렌더 계산의 실행 시점이 다르며 element는 DOM 노드 자체가 아니다. |
| 전체 관계·조건 설명 | JSX 소스→JavaScript 변환→현재 입력으로 컴포넌트 실행→React element의 노드 4개·간선 3개다. 도구의 변환과 렌더 계산의 실행 시점이 다르며 element는 DOM 노드 자체가 아니다. 모바일에서도 노드와 연결 방향·독립 경로가 같다. |
| 장면 | 현재 관찰값 | 설명 | 변화 이유 |
|---|---|---|---|
| JSX 작성 | source: JSX / 현재 값: 아직 실행 전 | 태그/props/표현식이 변환 입력에 있다 | JSX는 실제 HTML 문자열을 바로 표시하는 것이 아니다 |
| JavaScript 변환 | 산출: React element 생성 코드 / DOM: 아직 없음 | 도구가 실행 가능한 JS로 변환한다 | 변환 시점과 컴포넌트 입력 평가 시점은 다르다 |
| 현재 입력 평가 | 입력: 현재 props/state / 결과: element 값 | 컴포넌트가 현재 값을 읽어 element UI 설명을 반환한다 | element는 DOM 노드 자체가 아니며 commit은 별도다 |
위 그림은 JSX 소스가 React element가 되기까지의 네 단계를 보여 줍니다. 태그와 props, 표현식으로 쓴 JSX 소스를 개발·빌드 도구가 자바스크립트로 변환하고, 컴포넌트가 실행될 때 현재 입력을 평가해, UI를 기술하는 값인 React element를 만듭니다. 그림의 핵심은 태그를 작성하고 변환하는 시점과 name, price 같은 값이 평가되는 시점이 다르다는 점이며, React element는 화면의 구조를 기술하는 값일 뿐 DOM 노드 자체가 아닙니다. 그 뒤에 React가 렌더 결과를 DOM에 반영합니다.
그림의 첫 번째 상세 단계에서 <h2>{name}</h2>와 <p>가격: {price}원</p> 두 태그는 부모 요소나 Fragment 안에 씁니다. 도구는 JSX를 자바스크립트 함수 호출로 바꾸며, 그 호출의 모양은 프로젝트의 JSX 런타임 설정에 따라 달라집니다. 두 번째 단계에서 ProductCard가 호출되면 name: "키보드", price: 30000처럼 현재 props를 읽어, 제목 “키보드”와 “가격: 30000원”을 기술하는 React element 트리를 돌려줍니다. 그림 아래의 두 문법 점검 항목, 곧 인접한 JSX를 묶고 태그를 닫는 구조의 규칙과 className·htmlFor·onClick 같은 속성 이름과 중괄호 표현식의 규칙은 이 글의 뒤에서 하나씩 살펴봅니다.
JSX란 무엇인가?
JSX는 JavaScript XML의 약자로, 이름처럼 자바스크립트 코드 안에 XML이나 HTML과 비슷한 구문을 쓸 수 있게 해 주는 문법 확장이며, React에서 UI를 기술할 때 씁니다. JSX를 읽을 때는 태그의 구조, 중괄호 안의 표현식, 속성 이름의 규칙이라는 세 부분으로 나눠 보면 이해하기 쉽습니다. 개발 도구는 JSX를 자바스크립트 함수 호출로 바꾸고, 컴포넌트가 실행될 때 그 호출이 현재 값으로 React element를 만듭니다. 이 값은 화면의 구조를 기술할 뿐, 그 자체가 브라우저의 DOM 노드는 아닙니다.
JSX는 HTML처럼 보이지만 실제로는 자바스크립트 코드의 일부입니다. 그래서 태그 사이에 자바스크립트 표현식을 넣을 수 있고, 복잡한 조건이나 반복은 함수의 다른 부분에서 계산해 가져올 수 있습니다. 웹 브라우저는 JSX를 직접 이해하지 못하므로, JSX 코드는 Babel이나 Oxc 같은 변환 도구가 일반 자바스크립트로 바꾼 뒤에 브라우저에서 실행됩니다. Vite 프로젝트에서는 이 변환이 개발 서버와 빌드 과정에 기본으로 들어 있습니다. 또 JSX는 무엇을 보여 줄지를 선언하는 방식이라, UI의 구조를 한눈에 파악하기 쉽게 만들어 줍니다.
더 깊이: JSX가 바뀌는 함수 호출의 두 가지 모양
JSX를 어떤 함수 호출로 바꿀지는 JSX 런타임(JSX runtime) 설정이 정합니다. 예전의 클래식 런타임(classic runtime)은 JSX를 React.createElement(...) 호출로 바꿨기 때문에, JSX를 쓰는 파일마다 React를 import해 두어야 했습니다. 2020년에 나온 자동 런타임(automatic runtime)은 <h1>Hello world</h1>를 react/jsx-runtime에서 자동으로 가져온 jsx 함수의 호출로 바꾸고, 자식은 children prop에 담아 넘깁니다(React 블로그의 새 JSX 변환 소개). Vite의 React 플러그인도 기본으로 자동 런타임을 쓰므로, 이 교재의 예제 파일은 JSX만 쓸 때 React를 import하지 않습니다.
React 19부터는 자동 런타임이 사실상 필수입니다. React 19 업그레이드 안내에 따르면 ref를 prop으로 받는 기능과 JSX의 속도 개선이 새 변환을 전제로 하므로, 오래된 변환을 쓰는 앱에는 outdated JSX transform이라는 문구가 담긴 경고가 나타납니다. 또 react/jsx-runtime과 개발용 react/jsx-dev-runtime의 함수는 컴파일러가 만든 코드에서만 부르도록 만들어진 것이라 직접 호출하지 않습니다. JSX 없이 element를 만들어야 한다면 공개 API인 createElement를 씁니다.
JSX의 기본 규칙
JSX는 HTML과 비슷하지만 몇 가지 중요한 규칙을 따릅니다. 이 규칙을 정확히 알아 두면 오류가 난 곳을 빨리 찾을 수 있습니다.
항상 하나의 루트(Root) 요소 반환
여러 JSX 태그를 하나의 표현식으로 돌려주려면 부모 요소나 프래그먼트로 묶어야 합니다. 이 제한은 하나의 JSX 표현식 안에서 인접한 태그를 묶어야 한다는 뜻이지, 화면에 두 요소를 나란히 놓을 수 없다는 뜻은 아닙니다. 배열처럼 다른 React 노드를 돌려주는 방법과도 구별합니다.
// ⭕ 올바른 예시: 하나의 div로 감싸져 있음
function MyComponent() {
return (
<div>
<h1>안녕하세요!</h1>
<p>리액트를 배워봅시다.</p>
</div>
);
}
// ❌ 잘못된 예시: 두 개의 최상위 요소
// function MyComponent() {
// return (
// <h1>안녕하세요!</h1>
// <p>리액트를 배워봅시다.</p>
// );
// }불필요한 <div>를 더하고 싶지 않다면 프래그먼트(Fragment)를 씁니다. 프래그먼트는 <></>나 <Fragment></Fragment>로 쓰며, 실제 DOM에는 아무 요소도 만들지 않고 묶는 역할만 합니다.
// ⭕ 올바른 예시: 프래그먼트 사용
import { Fragment } from 'react'; // 명시형 Fragment를 쓸 때만 가져옵니다.
function MyComponent() {
return (
<> {/* 단축 문법: <Fragment>와 같은 묶음 역할 */}
<h1>안녕하세요!</h1>
<p>리액트를 배워봅시다.</p>
</>
);
}
// 또는 명시적으로
function MyComponentWithFragment() {
return (
<Fragment>
<h1>안녕하세요!</h1>
<p>리액트를 배워봅시다.</p>
</Fragment>
);
}프래그먼트는 여러 컴포넌트를 묶어 돌려주거나 리스트를 렌더링할 때 특히 유용합니다.
HTML 속성 이름의 CamelCase 규칙
JSX에서는 HTML의 속성(attribute) 이름을 자바스크립트의 camelCase 규칙에 맞춰 씁니다. React DOM에 넘기는 프로퍼티 이름을 쓰기 때문입니다. 예를 들어 class는 className, for는 htmlFor, tabindex는 tabIndex, onclick은 onClick이 됩니다. 다만 모든 HTML 속성을 기계적으로 바꾸지는 않으며, aria-label이나 data-testid처럼 aria-*와 data-*로 시작하는 이름은 하이픈을 그대로 둡니다.
function MyButton() {
return (
<button className="my-button" onClick={() => console.log('클릭!')}>
클릭해주세요
</button>
);
}
// HTML에서는 다음과 같았겠죠?
// <button class="my-button" onclick="console.log('클릭!')">
// 클릭해주세요
// </button>JSX의 onClick에는 따옴표 안의 코드 문자열이 아니라 함수를 중괄호로 넘긴다는 점도 HTML과 다릅니다. 이 버튼을 누르면 넘긴 화살표 함수가 실행되어 브라우저 콘솔에 클릭!이 찍힙니다.
자식 요소가 없는 태그는 항상 닫기
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>닫지 않은 <img>는 JSX에서 문법 오류이므로, 브라우저에서 실행되기 전에 빌드 단계에서 어느 줄이 문제인지 알려 줍니다. 자식 요소가 있는 태그는 HTML과 똑같이 시작 태그와 종료 태그를 씁니다.
<div>
<p>이것은 단락입니다.</p>
</div>반대로 자식이 없는 <div></div>는 <div />처럼 스스로 닫는 형태로 줄여 쓸 수 있습니다. HTML과 달리 JSX에서는 어떤 태그든 이 형태로 쓸 수 있습니다.
자바스크립트 표현식 삽입: {} 중괄호
JSX 안에 자바스크립트의 변수나 함수 호출 결과, 그 밖의 표현식을 넣고 싶다면 중괄호 {}를 씁니다. 중괄호 안에는 값을 만들어 내는 식(expression)만 들어갈 수 있습니다. 아래 코드의 변수, 함수 호출, 삼항 연산자, 메서드 호출은 모두 계산하면 값 하나가 되는 식이라서 넣을 수 있습니다.
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>
);
}{변수명}은 변수의 값을, {함수명()}은 함수가 돌려준 값을 렌더링하며, {조건 ? 참일 때 : 거짓일 때}처럼 삼항 연산자로 조건에 따라 다른 내용을 보여 줄 수도 있습니다. 위 코드의 화면에는 “안녕하세요, 김코딩님!”, “나이: 30”, “저는 학생입니다.”와 함께, 실행한 날짜가 브라우저의 지역 설정에 맞는 형식으로 나타납니다. 반면 JSX 안에서는 if나 for 같은 제어문을 직접 쓸 수 없으므로, 삼항 연산자나 논리 연산자(&&, ||), 배열의 map() 메서드로 조건을 처리하거나 반복되는 요소를 렌더링합니다. 이 방법은 3장에서 자세히 다룹니다.
중괄호는 값을 계산하는 자리이지, 어떤 값이든 화면의 자식으로 보여 줄 수 있는 자리는 아닙니다. 문자열과 숫자는 그대로 보여 줄 수 있지만 일반 객체를 그대로 자식으로 두면 오류가 나므로, 객체의 속성이나 보여 줄 문자열을 골라 넣어야 합니다. 객체를 style이나 컴포넌트의 입력으로 넘기는 것은 이 자식 표시 문제와는 다른 이야기입니다(React 문서의 중괄호를 사용한 JSX 안의 자바스크립트).
JSX 내부의 주석
JSX 안에서 주석을 쓰는 방법은 일반 자바스크립트와 조금 다릅니다. 태그 사이에서는 중괄호 {} 안에 자바스크립트 주석을 써야 합니다.
function CommentExample() {
return (
<div>
{/* 이것은 JSX 내부의 주석입니다 */}
<h1>JSX 주석 예시</h1>
{
// 여러 줄 주석도 가능합니다.
// 이 주석은 화면에 렌더링되지 않습니다.
}
<p>주석은 코드를 설명하는 데 유용합니다.</p>
</div>
);
}태그 사이에 // 주석을 중괄호 없이 그냥 적으면 주석이 아니라 일반 텍스트로 취급되어 화면에 그대로 나타납니다. 중괄호 안의 // 주석은 줄 끝까지를 주석으로 보므로, 위 코드처럼 닫는 중괄호를 다음 줄에 둡니다.
JSX의 활용 예시
간단한 예제로 JSX의 쓰임을 다시 한번 살펴봅니다. 아래 ProductCard는 앞에서 본 규칙을 한 컴포넌트에 모은 것이므로, 읽을 때는 className, 중괄호로 넣은 속성 값, 삼항 연산자, onClick이 각각 어느 줄에 있는지 찾아보면 됩니다. 첫 줄에서 props 객체의 네 값을 구조 분해로 꺼내 두었으므로, JSX 안에서는 props.name 대신 name만 씁니다.
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를 동적으로 구성합니다. class 대신 className="product-card"를 썼고, 이미지의 src 속성에는 src={imageUrl}로 자바스크립트 변수를 넣었습니다. onClick={() => ...}에는 이벤트 처리 함수를 직접 넘겼으며, 이 버튼은 알림만 띄울 뿐 장바구니 데이터를 실제로 추가하거나 서버에 저장하지는 않습니다.
재고 문구의 style={{ color: 'green', fontWeight: 'bold' }}는 style 속성에 자바스크립트 객체로 CSS 속성을 직접 준 것입니다. 바깥쪽 중괄호는 JSX의 표현식 자리이고 안쪽 중괄호는 객체를 뜻하며, CSS 속성의 이름도 font-weight가 fontWeight가 되는 것처럼 camelCase로 씁니다. 이 예제를 읽을 때는 속성과 중괄호 표현식, 조건부 렌더링, 이벤트 처리 함수가 각각 어떤 역할을 맡는지 나눠 보세요.
이번에는 직접 계산 결과를 예상해 봅니다. 앞 장 프로젝트의 src/App.jsx를 아래 코드로 바꾸고 저장합니다. 계산은 중괄호 안에서만 일어나며, 따옴표로 감싼 속성 값이나 태그 안의 일반 텍스트는 그대로 전달됩니다.
export default function App() {
const item = { name: '키보드', price: 30000 };
return (
<>
<p>{item.name}: {item.price + 1000}원</p>
<p>item.price + 1000</p>
<p data-testid="total" aria-label="배송비 포함 가격">
{item.price + 1000}
</p>
</>
);
}화면의 첫 문장은 키보드: 31000원, 둘째 문장은 item.price + 1000, 셋째 문장은 31000입니다. 첫 문장과 셋째 문장은 중괄호 안에서 가격에 1000을 더해 계산했고, 둘째 문장은 중괄호가 없어 글자 그대로 보입니다. 첫 문장은 item 객체를 그대로 보여 준 것이 아니라 문자열 속성과 숫자 계산의 결과를 골라 넣은 것이며, 앞의 ProductCard도 같은 방식으로 이름과 가격, 재고 여부를 읽습니다. 셋째 문장의 data-testid와 aria-label은 하이픈을 그대로 둔 속성입니다.
정리
- JSX는 자바스크립트 안에 HTML과 비슷한 구문을 쓰는 문법 확장이며, 변환 도구가 자바스크립트 호출로 바꾸고 실행할 때 현재 값으로 React element를 만듭니다.
- React element는 UI의 구조를 기술하는 값이며 DOM 노드 자체가 아닙니다.
- 인접한 JSX 태그는 하나의 부모 요소나 프래그먼트로 묶고, 자식이 없는 태그는
<img />처럼 스스로 닫습니다. - 속성은
className,htmlFor,onClick처럼 camelCase로 쓰되,aria-*와data-*는 하이픈을 유지합니다. - 중괄호 안에는 자바스크립트 표현식을 넣으며, 문자열과 숫자는 보여 줄 수 있지만 일반 객체를 자식으로 두면 오류가 납니다.
- JSX 안의 주석은
{/* … */}처럼 중괄호 안에 씁니다.
연습 문제
1. 상품 바꾸기
위 App.jsx의 상품을 이름 마우스, 가격 15000으로 바꾸면 세 문장은 각각 무엇이 될까요? 실행하기 전에 먼저 적어 보세요.
해설 보기
세 문장은 마우스: 16000원, item.price + 1000, 16000입니다. 첫 문장과 셋째 문장은 중괄호 안에서 배송비 1000을 숫자로 더했고, 둘째 문장은 중괄호가 없어 계산하지 않고 글자 그대로 보입니다.
2. 객체를 그대로 넣으면
1번의 코드에서 첫 문장의 item.name을 item으로만 바꾸면 어떻게 될까요? 이것은 가격 계산의 문제일까요, 자식을 표시하는 문제일까요?
해설 보기
item은 일반 객체라서 첫 문장의 자식으로 표시할 수 없으므로 렌더링 오류가 납니다. 개발 모드의 Console에는 Objects are not valid as a React child (found: object with keys {name, price})로 시작하는 오류가 나타납니다.
더하기 계산의 문제가 아니라 자식을 표시하는 문제입니다. 오류를 확인한 뒤에는 item.name처럼 보여 줄 속성으로 되돌립니다.
다음 글 컴포넌트의 개념과 종류에서는 이 JSX를 재사용할 수 있는 UI 단위인 컴포넌트로 나누는 방법을 다룹니다.