Skip to Content
WebReactReact 기초02. JSX 문법

이번 편의 결과물: (코드 없음) JSX 문법 규칙을 정리하고, 브라우저에서 JSX 코드와 그 변환 결과(React.createElement 호출)를 나란히 비교합니다. · 다루는 개념: JSX = JS 표현식, 태그·속성·중괄호 표현식 규칙, JSX가 React.createElement 호출로 바뀐다는 개념

이 편에서 만드는 파일

이 편도 이론 편이라 로컬 파일을 만들지 않습니다. 03편에서 bookshelf 프로젝트를 만든 뒤 04편부터 실제 파일에 JSX를 작성합니다.

개념 정리

JSX는 JS 표현식이다

JSX(JavaScript XML)는 HTML과 비슷하게 생겼지만 실제로는 JavaScript 표현식입니다. 빌드 도구(Vite가 내부적으로 사용하는 Babel 계열 변환기)가 JSX 코드를 React.createElement 함수 호출로 바꾼 뒤에야 브라우저에서 실행됩니다.

const element = <h1>안녕하세요</h1>;

위 코드는 빌드 시점에 아래와 같은 형태로 변환됩니다.

const element = React.createElement('h1', null, '안녕하세요');

createElement는 태그 이름, 속성(props) 객체, 자식 내용을 인자로 받아 화면을 그리는 데 필요한 정보만 담은 일반 JS 객체를 반환합니다. 이 객체를 리액트 엘리먼트라고 부릅니다. JSX는 이 객체를 눈에 익은 태그 형태로 편하게 쓰기 위한 문법 설탕(syntactic sugar)입니다.

태그 규칙

규칙설명
반드시 닫는다<img>처럼 HTML에서 생략 가능한 태그도 JSX에서는 <img />처럼 self-closing으로 닫는다
루트 하나컴포넌트는 최상위 요소 하나만 반환한다. 여러 요소를 나란히 두려면 <>...</>(Fragment)로 감싼다
속성은 camelCaseHTML의 classclassName, onclickonClick으로 쓴다
대소문자로 구분소문자로 시작하면 HTML 태그, 대문자로 시작하면 사용자 정의 컴포넌트로 해석한다
// 잘못된 예: 루트가 두 개 function Bad() { return ( <h1>제목</h1> <p>본문</p> ); }
// 올바른 예: Fragment로 감싼다 function Good() { return ( <> <h1>제목</h1> <p>본문</p> </> ); }

중괄호 표현식 규칙

JSX 태그 안에서 {}를 쓰면 그 안은 다시 JavaScript 표현식으로 해석됩니다. 변수, 함수 호출, 삼항 연산자 등 값을 만드는 표현식만 넣을 수 있고, if문 같은 문(statement)은 넣을 수 없습니다.

넣을 수 있는 것넣을 수 없는 것
변수: {title}if/for
함수 호출 결과: {formatDate(date)}변수 선언(const x = 1)
삼항 연산자: {isDone ? '완료' : '진행 중'}다중 문장 블록
배열의 map 결과-
function Greeting({ name }) { const hour = new Date().getHours(); return <p>{hour < 12 ? '좋은 아침입니다' : '안녕하세요'}, {name}님</p>; }

속성 값도 표현식이다

문자열 리터럴은 따옴표로, 그 외 값(숫자, 변수, 객체)은 중괄호로 감쌉니다.

<input type="text" maxLength={20} value={title} disabled={isLoading} />

style 속성은 문자열이 아니라 JS 객체를 받습니다. 속성 이름도 camelCase입니다.

<div style={{ backgroundColor: '#2563eb', fontSize: 14 }}>표지</div>

바깥쪽 중괄호는 “여기부터 JS 표현식”이라는 뜻이고, 안쪽 { backgroundColor: ... }는 그 표현식이 만드는 객체 리터럴입니다.

실습

브라우저에서 같은 화면을 JSX로 쓴 버전과 React.createElement로 직접 쓴 버전을 나란히 실행해 결과가 같은지 확인합니다.

export default function App() {
const bookTitle = '클린 코드';

// JSX로 작성한 엘리먼트
const withJsx = <p className="title">{bookTitle}</p>;

// 같은 결과를 React.createElement로 직접 작성
const withCreateElement = React.createElement(
  'p',
  { className: 'title' },
  bookTitle
);

console.log('JSX 엘리먼트:', withJsx);
console.log('createElement 엘리먼트:', withCreateElement);

return (
  <div>
    {withJsx}
    {withCreateElement}
  </div>
);
}

콘솔에 찍힌 두 객체의 type, props 값을 비교합니다. type은 둘 다 p이고, props는 둘 다 { className: 'title', children: '클린 코드' } 형태입니다. JSX가 결국 같은 모양의 객체를 만든다는 뜻입니다.

직접 해보기

  1. 위 예제의 bookTitle을 책 제목과 저자를 함께 담은 문자열로 바꾸고, 콘솔에서 props.children 값이 어떻게 바뀌는지 확인합니다.
  2. withJsx<p className="title" data-testid="book-title">{bookTitle}</p>로 바꾼 뒤, 콘솔에 찍힌 props 객체에 data-testid 키가 추가되었는지 확인합니다.

정답 보기

const bookTitle = '클린 코드 - 로버트 C. 마틴'; const withJsx = <p className="title" data-testid="book-title">{bookTitle}</p>;

콘솔에는 props: { className: 'title', 'data-testid': 'book-title', children: '클린 코드 - 로버트 C. 마틴' } 형태가 찍힙니다.

자주 하는 실수

증상원인고치는 법
Adjacent JSX elements must be wrapped 에러컴포넌트가 최상위 요소를 두 개 이상 반환<>...</> Fragment 또는 <div>로 감싼다
class 속성이 화면에 적용 안 됨HTML 속성 이름 class를 그대로 사용className으로 바꾼다
style 속성에서 에러 발생style="color: red"처럼 문자열로 작성style={{ color: 'red' }} 객체로 작성한다
중괄호 안에 if문을 넣어 에러문(statement)을 표현식 자리에 사용삼항 연산자나 함수로 표현식화한다

확인 문제

문제 14지선다
JSX가 브라우저에서 실행되기 전 변환되는 형태는?
문제 24지선다
JSX에서 컴포넌트가 요소 두 개를 나란히 반환하려 할 때 올바른 방법은?
문제 34지선다
JSX 중괄호 표현식 자리에 넣을 수 있는 것은?
문제 44지선다
JSX에서 인라인 스타일을 지정하는 올바른 방법은?

참고 자료

Last updated on