Skip to content
This page has been auto-translated and may contain errors.View in English

JSX

순수 JavaScript로 UI를 만들려면 여러 단계를 거쳐야 합니다. 요소를 생성하고, 클래스를 지정하고, 텍스트를 설정한 다음, 페이지에 붙이는 식입니다. 마크업과 그것을 동작시키는 코드가 떨어져 있어서, UI가 커질수록 둘을 동기화하기 어려워집니다. **JSX**는 이 간격을 좁혀줍니다. 마크업이 JavaScript 안에 직접 들어가서, 템플릿과 스크립트를 따로 관리하는 대신 자유롭게 섞어서 사용할 수 있습니다.

JavaScript 안의 마크업

JSX는 JavaScript이므로, 중괄호 {}로 감싸면 어떤 JavaScript 표현식이든 넣을 수 있습니다. 변수든, 함수 호출이든, 계산이든, 필요한 어떤 값이든 정적인 텍스트를 쓰는 자리에 그대로 마크업에 들어갑니다.

jsx
const name = 'Ada'
return <p className="greeting">Hello, {name}</p>

여기서 {name}은 렌더링될 때 name 변수의 값으로 바뀌므로, 페이지에는 "Hello, Ada"가 표시됩니다. 중괄호 바깥은 모두 마크업이고, 안은 순수 JavaScript입니다.

JSX에는 몇 가지 규칙이 있습니다. 대부분의 속성은 HTML이 사용하는 소문자와 하이픈 형태 대신 camelCase를 사용하므로, class, for, tabindex 대신 className, htmlFor, tabIndex입니다. 다만 ARIA와 data- 속성은 하이픈을 유지해서 aria-hiddendata-testid 같이 씁니다. 모든 태그는 닫아야 하는데, HTML에서는 열어만 두는 태그도 포함해서 <img /><br />처럼 닫는 슬래시가 필요합니다. 그리고 컴포넌트는 하나의 루트 요소만 반환할 수 있습니다. 추가 <div>로 감싸지 않고 두 개의 형제 요소를 반환해야 한다면, 빈 꺾쇠괄호로 된 fragment로 감싸면 됩니다.

jsx
return (
  <>
    <h1>Title</h1>
    <p>Some text</p>
  </>
)

JSX와 HTML의 차이점

JSX는 HTML과 충분히 닮아 있어서 차이점을 놓치기 쉬운데, 문제가 될 때까지 눈에 띄지 않습니다. 가장 먼저 눈에 띄는 것은 속성 이름입니다. classclassName이 되는데, class는 JavaScript의 예약어이기 때문입니다. style 속성도 다릅니다. HTML에서는 CSS 문자열이지만, JSX에서는 JavaScript 객체이며, 속성 이름은 camelCase이고 값은 문자열입니다.

jsx
<div style={{ backgroundColor: 'lightblue', fontSize: '18px' }}>Styled</div>

바깥쪽 {}는 표현식을 포함하는 같은 것이고, 안쪽 {}는 포함되는 객체 리터럴이라서, JSX의 style 속성은 중괄호가 연달아 두 개 나타나게 됩니다.

다른 차이점은 {} 안에 뭘 넣을 수 있느냐입니다. **표현식**만 허용되는데, 이는 값을 산출하는 것들 — 변수, 함수 호출, 삼항 연산자 같은 것입니다. 문(statement)은 허용되지 않으므로, iffor 루프를 마크업의 중괄호 안에 직접 넣을 수 없습니다. 그런 종류의 로직이 필요할 때는 return 위에서 실행하고 결과를 포함시키면 됩니다.

내부적으로 JSX는 브라우저에 도달하기 전에 순수 JavaScript 함수 호출로 컴파일됩니다. 이는 매일 생각할 문제보다는 도구 관련 세부 사항이고, Beyond the basics 장에서 React의 나머지 부분이 준비되면 다시 다룹니다.

JSX는 문법 설탕입니다. 컴파일러는 각 요소를 React.createElement 호출이나, 이 과정에서 사용하는 자동 JSX 런타임(React 17 이후 표준이며, 현대적인 어떤 설정에서든 기본값)의 동등한 호출로 변환합니다. React가 범위에 있을 필요가 없습니다. 앞의 예는 대략 React.createElement('p', { className: 'greeting' }, 'Hello, ', name) 같은 형태로 컴파일됩니다.

이 컴파일 단계가 정확히 {}가 표현식만 보유하는 이유입니다. 각 {}는 그 함수 호출로 전달되는 인자가 되고, 함수 인자는 값으로 평가되어야 합니다. iffor 같은 문은 값을 산출하지 않으므로, 인자가 기대되는 자리에 올 수 없습니다. 삼항 연산자는 표현식이므로 인라인으로 작동하지만, if는 문이므로 그렇지 않습니다. 로직이 삼항 연산자로 깔끔하게 담기기보다 복잡하면, return 위의 변수에서 값을 계산하고 그 변수를 포함시키면 됩니다.

JunoJSX는 JavaScript가 섞인 마크업입니다 꼭 기억할 한 가지: {}는 마크업 안에서 JavaScript로 돌아가는 입구입니다. 중괄호 사이의 모든 것은 값이고, 변수고, 계산이고, 함수 호출이며, 페이지에 바로 떨어집니다. 나머지는 모두 여기서 따라옵니다. class 대신 className, 모든 태그를 닫기, 그리고 반환마다 하나의 루트 요소입니다.
JunoJSX는 JavaScript가 섞인 마크업입니다{}를 표현식 슬롯이라고 생각하세요. 변수, 함수 호출, 삼항 연산자는 모두 괜찮지만, if 같은 문은 안 됩니다. 이것을 이름 차이와 함께 생각하면 — className, htmlFor, 객체로서의 style — JSX가 HTML의 변형처럼 느껴지는 것이 멈추고, 그것이 정말 무엇인지(JavaScript가 마크업 문법을 입고 있는 것) 느껴지기 시작합니다.
JunoJSX는 JavaScript가 섞인 마크업입니다 모든 {}는 함수 인자로 컴파일되는데, 이것이 정확히 표현식이 그곳에서 작동하고 문은 그렇지 않은 이유의 전부입니다. 이 정신 모델을 유지하면, JSX의 나머지 이상한 점들 — camelCase 속성, 객체로서의 style, 자체 닫는 태그 — 이 임의의 규칙처럼 보이는 것이 멈추고, "React.createElement 호출이 위장한 것"의 결과처럼 보이기 시작합니다.

다음: 컴포넌트 스타일링에서 요소들의 모양을 살펴봅시다.