이 글에서 정리하는 내용
JSX를 HTML처럼 외우는 대신 JavaScript 안에서 UI를 표현하는 문법으로 이해합니다. 기본 문법, 중괄호 표현식, 조건부 렌더링, 리스트 렌더링과 style 같은 속성 바인딩, Fragment까지 한 흐름으로 정리합니다.
JSX는 무엇이고 왜 쓰는가

JSX는 React에서 자주 보이는 HTML 비슷한 문법이지만, 실제 HTML 파일 문법 자체는 아닙니다. JavaScript 파일 안에서 UI 구조를 더 읽기 쉽게 표현하기 위한 문법 확장이라고 이해하는 편이 정확합니다. 그래서 이 문법을 읽을 때는 태그 모양만 보는 것이 아니라이 코드가 결국 JavaScript 안에서 평가된다는 점을 같이 봐야 합니다.
처음에는 HTML을 그대로 옮겨 적는 느낌이 강하지만, 조금만 들어가 보면 차이가 분명합니다. 태그를 반드시 닫아야 하고, 여러 요소를 반환할 때 하나의 부모로 감싸야 하며, class 대신 을 쓰는 식으로 JavaScript 문법과 React 규칙이 섞여 있습니다. 특히 <img> 같은 단일 태그도 이 문법에서는 <img />처럼 명시적으로 닫아야 하므로, HTML보다 조금 더 엄격한 문법으로 보는 편이 좋습니다. 즉 이 구조는 마크업처럼 보이지만, 화면을 설명하는 JavaScript 코드에 더 가깝습니다.
HTML처럼 보여도 그대로 HTML은 아닙니다
// JSX는 JavaScript 안에서 UI를 표현하는 문법입니다.
function Greeting() { const name = '해비'; return ( <section> <h1>안녕하세요, {name}님</h1> <p>이 영역은 JSX로 작성한 UI입니다.</p> </section> );
}
위 코드는 화면에 제목과 문단을 그리는 예시이지만, HTML 파일에 직접 작성한 것이 아니라 함수 안에서 반환한 화면 구조입니다. 따라서 단순 마크업이 아니라 컴포넌트가 반환하는 값으로 이해해야 합니다. 이 감각이 잡혀야 이후 조건 분기나 리스트 출력도 자연스럽게 이어집니다.
중괄호로 JavaScript 넣기
이 문법에서 가장 중요한 요소 중 하나가 중괄호입니다. 중괄호는 화면 코드 안으로 JavaScript 값을 가져오는 통로입니다. 문자열을 그대로 넣고 싶다면 따옴표를 쓰면 되고, 변수나 계산 결과처럼 JavaScript가 평가한 값을 넣고 싶다면 중괄호를 사용합니다.
여기서 핵심은 아무 코드나 넣는 것이 아니라 값으로 평가될 수 있는 표현식을 넣는다는 점입니다. 변수, 숫자 계산, 문자열 결합, 함수 호출 결과 삼항 연산자 결과처럼 최종적으로 어떤 값이 되는 것들은 중괄호 안에 넣을 수 있습니다. 반대로 문장 자체를 그대로 넣는 방식으로 이해하면 금방 헷갈리게 됩니다.
문자열과 표현식은 넣는 방식이 다릅니다
// 따옴표는 문자열, 중괄호는 JavaScript 값입니다.
function Profile() { const nickname = '몽이'; const age = 4; const isAdult = age >= 20; return ( <div className="profile-card" title={nickname}> <p>이름: {nickname}</p> <p>나이: {age}</p> <p>성인 여부: {isAdult ? '성인' : '미성년자'}</p> </div> );
}
처럼 따옴표를 사용하면 단순 문자열이 들어갑니다. 반면 처럼 중괄호를 사용하면 JavaScript 변수 값이 들어갑니다. 처럼 삼항 연산자 결과도 화면 코드 안에서 바로 사용할 수 있습니다.
| 형태 | 의미 |
|---|---|
| title=”hello” | 문자열 hello를 그대로 전달 |
| title={nickname} | nickname 변수의 값을 전달 |
조건부 렌더링과 리스트 렌더링
React에서는 화면 분기를 위한 별도 템플릿 문법을 배우기보다, 익숙한 JavaScript 조건문을 화면 구조와 함께 사용합니다. 그래서 조건부 렌더링은 React 전용 문법을 외우는 방식보다, 어떤 경우에 어떤 UI를 보여줄지 JavaScript로 분기한다고 이해하는 편이 더 정확합니다.
또한 여러 개의 비슷한 UI를 반복해서 출력할 때는 배열을 으로 순회하면서 요소를 반환합니다. 이 흐름이 익숙해지면 메뉴 목록, 카드 목록, 댓글 목록처럼 실무에서 자주 다루는 반복 UI를 훨씬 자연스럽게 작성할 수 있습니다.
조건에 따라 다른 UI를 보여주기
// 조건부 렌더링은 JavaScript 분기를 사용합니다.
function LoginStatus() { const isLoggedIn = true; const unreadCount = 3; return ( <section> <h2>알림</h2> {isLoggedIn ? ( <p>새 알림이 {unreadCount}개 있습니다.</p> ) : ( <p>로그인이 필요합니다.</p> )} {unreadCount > 0 && <button>알림 확인</button>} </section> );
}
삼항 연산자는 둘 중 하나를 분명하게 골라야 할 때 적합하고는 조건이 참일 때만 짧게 어떤 요소를 추가하고 싶을 때 자주 사용합니다. 복잡한 분기는 컴포넌트 위쪽에서 로 나눈 뒤 반환하는 편이 더 읽기 좋을 때도 많습니다.
배열을 map으로 돌려 목록 출력하기
// 리스트 렌더링에서는 key를 함께 지정합니다.
function MenuList() { const menus = [ { id: 1, name: '아메리카노' }, { id: 2, name: '라떼' }, { id: 3, name: '바닐라 콜드브루' }]; return ( <ul> {menus.map((menu) => ( <li key={menu.id}>{menu.name}</li> ))} </ul> );
}
배열을 으로 돌릴 때는 각 항목이 어떤 요소로 바뀌는지를 한눈에 볼 수 있어야 합니다. 또한 목록에서는 를 함께 넣어야 React가 각 항목을 안정적으로 구분할 수 있습니다. 이때 는 렌더링마다 바뀌는 값보다 데이터에 이미 들어 있는 안정적인 ID를 쓰는 편이 좋고, 순서가 바뀔 수 있는 목록에서 인덱스를 그대로 로 쓰면 추적이 꼬일 수 있습니다. 이 패턴은 상품 리스트, 방명록, 탭 메뉴, 카드형 UI 등 거의 모든 반복 렌더링에 공통으로 쓰입니다.
, style, 속성 바인딩과 Fragment

이 문법에서는 HTML 속성을 그대로 옮겨 적는 것처럼 보여도 실제로는 JavaScript 값과 연결되는 경우가 많습니다. 대표적으로같은 속성들은 문자열로 넣을 수도 있고, 변수나 조건식 결과를 넣을 수도 있습니다. 그래서 속성 바인딩은 마크업 작성이라기보다 UI 상태를 값으로 연결하는 작업에 가깝습니다.
Fragment는 여러 요소를 묶어 반환해야 하지만 불필요한 를 추가하고 싶지 않을 때 사용합니다. 레이아웃을 위한 wrapper가 실제 DOM에 꼭 필요하지 않은 상황이라면 Fragment를 써서 구조를 더 깔끔하게 유지할 수 있습니다.
속성 바인딩과 style 객체 이해하기
// style은 객체로 넣고, className은 문자열 또는 표현식으로 넣습니다.
function ProductCard() { const isSoldOut = false; const cardClassName = isSoldOut ? 'card soldout' : 'card'; const priceColor = isSoldOut ? '#999' : '#111'; return ( <article className={cardClassName} style={{ padding: '16px', color: priceColor }} aria-hidden={false} > <h3>프리미엄 청첩장</h3> <button disabled={isSoldOut}> {isSoldOut ? '품절' : '구매하기'} </button> </article> );
}
에는 문자열을 직접 넣을 수도 있고, 조건식 결과를 넣을 수도 있습니다. 은 특수한 새로운 문법처럼 느껴질 수 있지만, 실제로는 중괄호 안에 JavaScript 객체를 넣는 형태입니다. 값이 JavaScript 상태와 연결될 때는 이런 방식이 특히 유용합니다.
불필요한 div 없이 묶고 싶다면 Fragment
// Fragment는 여러 JSX 요소를 그룹으로 묶을 때 사용합니다.
function PageHeader() { return ( <> <h1>주문 내역</h1> <p>최근 30일 기준으로 정리했습니다.</p> </> );
}
짧은 문법인 는 Fragment 축약형입니다. 화면에는 제목과 문단이 나란히 렌더링되지만이를 감싸는 추가 DOM 요소는 생기지 않습니다. 다만 목록 안에서 여러 요소를 한 묶음으로 반환하면서 까지 넣어야 한다면 축약형 대신 <Fragment key={...}> 형태를 사용해야 합니다. 레이아웃 구조를 최소화하고 싶을 때 매우 자주 쓰이는 패턴입니다.
정리
이 주제를 처음 공부할 때 가장 중요한 관점은 HTML처럼 생긴 코드라는 인상에서 한 단계 더 나아가는 것입니다. 이 문법은 JavaScript 안에서 UI를 설명하기 때문에, 변수 출력도 되고 조건 분기도 되고 배열 반복도 됩니다. 결국 이를 잘 읽는다는 것은 마크업과 로직이 만나는 지점을 자연스럽게 해석할 수 있다는 뜻입니다.
정리하면, 문자열은 따옴표로 넣고 JavaScript 값은 중괄호로 넣습니다. 조건부 렌더링은 삼항 연산자, 분기로 나눠 생각하면 됩니다. 반복 UI는 으로 만들고, 속성은 값에 따라 바인딩하며, 불필요한 감싸기 요소를 줄이고 싶다면 Fragment를 사용하면 됩니다. 이 흐름이 익숙해지면 이 문법은 더 이상 낯선 형식이 아니라 React UI를 읽는 기본 언어처럼 느껴지게 됩니다.
많이 받는 질문
Q. JSX는 결국 HTML과 같은 건가요?
같아 보이지만 같지 않습니다. HTML 비슷한 문법으로 UI를 표현하지만, 실제로는 JavaScript 안에서 동작하는 React 코드입니다.
Q. 중괄호 안에는 무엇이든 넣을 수 있나요?
값으로 평가되는 표현식을 넣는다고 이해하는 편이 좋습니다. 변수, 계산식, 함수 호출 결과 삼항 연산자 결과처럼 최종적으로 값이 되는 것들이 주로 들어갑니다.
Q. 리스트 렌더링에서 key는 왜 필요한가요?
React가 각 항목을 구분해 어떤 항목이 추가, 삭제이동됐는지 파악하기 위해 필요합니다. 가능하면 데이터 기반의 안정적인 ID를 쓰는 편이 좋습니다.
Q. Fragment와 div는 어떻게 다르나요?div는 실제 DOM 요소가 추가되지만 Fragment는 여러 JSX 요소를 묶기만 하고 추가 DOM을 만들지 않습니다. 구조를 불필요하게 늘리고 싶지 않을 때 Fragment가 적합합니다.
같이 읽으면 좋은 글
- React 처음 배우는 순서: 컴포넌트부터 state, Zustand까지
- React state vs Zustand: 언제 전역 상태가 필요할까
- React useEffect 두 번 실행 문제 해결: Strict Mode에서 중복 호출 확인하기
“React JSX 문법 사용법: 조건부 렌더링과 리스트 처리”에 대한 2개의 생각