JSX파일
JSX는 JavaScript의 확장으로, JavaScript 파일 내에 HTML처럼 마크업을 작성할 수 있습니다. 컴포넌트를 작성할 수단은 그 외에도 존재하지만, 대부분의 React 개발자는 JSX의 간결함을 선호하기 때문에, 대부분 코드에 JSX가 사용된다.
JSX: JavaScript에 마크업을 삽입
이때까지는 HTML, CSS, JavaScript만을 사용해 페이지를 만들어왔다. 오랜 기간에 거쳐, 웹 개발자는 콘텐츠는 HTML으로 작성하고, 디자인은 CSS, 로직은 JavaScript 각각의 파일로 분리하여 만들어왔다. 콘텐츠가 HTML 내에 마크업되는 방법으로, 페이지 로직은 다른 파일의 JavaScript에 존재해온 형태였다.
그러나 웹이 좀 더 상호작용하는 형태로 변화하자, 로직이 콘텐츠를 결정하게 되었다. 이것이 React가 로직과 마크업을 같은 파일에 작성하는 컴포넌트를 만들게 된 이유이다.
버튼의 렌더링 로직과 마크업을 같은 파일에 작성하면, 코드 수정 시 동기화가 보장된다. 반대로, 버튼 마크업과 사이드바의 마크업은 각각 관계가 없기 때문에 분리되어 작성된다면 안전하고 독립된 파일의 갱신이 가능하다.
각각의 React 컴포넌트는 JavaScript의 함수 형태로, React가 브라우저에 표시하기 위한 마크업을 포함할 수 있다. JSX는 HTML과 비슷하게 생겼지만, 구문이 엄밀히 존재하며, 동적인 정보를 표시할 수 있다. 이해하기 위해선, HTML 마크업을 JSX 마크업으로 변환해보는 것이 좋다.
JSX와 React는 엄연히 다르다. 같이 사용되는 경우가 많지만 둘 다 각각 따로 사용하는 것이 가능하다. JSX는 언어의 확장이며, React는 JavaScript 라이브러리다.
HTML을 JSX로 변환하기
이런 HTML 파일이 있다고 가정하자
<h1>Hedy Lamarr's Todos</h1>
<img
src="https://i.imgur.com/yXOvdOSs.jpg"
alt="Hedy Lamarr"
class="photo"
>
<ul>
<li>Invent new traffic lights
<li>Rehearse a movie scene
<li>Improve the spectrum technology
</ul>
이것을 컴포넌트 내에 그대로 삽입한다고 생각하면 된다.
export default function TodoList() {
return (
// ???
)
}
그러나 그대로 복사해서 붙여넣기하는 것 만으로는 제대로 동작하지 않는다.
export default function TodoList() {
return (
// This doesn't quite work!
<h1>Hedy Lamarr's Todos</h1>
<img
src="https://i.imgur.com/yXOvdOSs.jpg"
alt="Hedy Lamarr"
class="photo"
>
<ul>
<li>Invent new traffic lights
<li>Rehearse a movie scene
<li>Improve the spectrum technology
</ul>
);
}
/src/App.js: Adjacent JSX elements must be wrapped in an enclosing tag.
Did you want a JSX fragment <>...</>? (5:4)
3 | // This doesn't quite work!
4 | <h1>Hedy Lamarr's Todos</h1> >
5 | <img |
^
6 | src="https://i.imgur.com/yXOvdOSs.jpg"
7 | alt="Hedy Lamarr"
8 | class="photo"
이건, JSX을 사용하는 방법이 엄밀하고, HTML보다 규칙이 많기 때문이다. 위의 에러 메시지에도 나와있지만, 다음 안내를 따르면 괜찮다.
대부분의 경우엔 React가 화면 상에 표시하는 에러 메시지가, 문제가 있는 코드 위치를 찾을 수 있는 단서가 된다.
JSX의 규칙
1. 단 하나의 루트 요소만을 반환한다.
컴포넌트에서 둘 이상의 요소를 반환하기 위해선, 하나의 태그로 묶어야한다.
예를 들어 <div>를 사용할 수 있다.
<div>
<h1>Hedy Lamarr's Todos</h1>
<img
src="https://i.imgur.com/yXOvdOSs.jpg"
alt="Hedy Lamarr"
class="photo"
>
<ul>
...
</ul>
</div>
마크업에 여유롭게 <div>를 추가할 수 없는 경우엔, 대신 <>과 </>를 사용할 수 있다.
<>
<h1>Hedy Lamarr's Todos</h1>
<img
src="https://i.imgur.com/yXOvdOSs.jpg"
alt="Hedy Lamarr"
class="photo"
>
<ul>
...
</ul>
</>
이 태그는 프래그먼트(Fragment)라고 불린다. 프래그먼트를 사용하면, 브라우저의 HTML 트리에는 존재하지 않지만, 두 개 이상의 요소를 묶을 수 있다.
2. 모든 태그에는 닫는 태그가 필요하다.
JSX에선 모든 태그를 명시적으로 닫아줄 필요가있다. <img>와 같은 자동으로 닫히는 태그는 <img />로 되고, <li>oranges와 같은 감싸는 태그는 <li>oranges</li>와 같은 식으로 작성해야한다.
Hedy Lamarr의 영상과 리스트 항목은, 닫기 태그를 작성한 상태에선 아래와 같이 변한다.
<>
<img
src="https://i.imgur.com/yXOvdOSs.jpg"
alt="Hedy Lamarr"
class="photo"
/>
<ul>
<li>Invent new traffic lights</li>
<li>Rehearse a movie scene</li>
<li>Improve the spectrum technology</li>
</ul>
</>
3. 대부분의 경우 카멜 케이스로 작성해야 한다.
JSX는 JavaScript로 변형되어, 안에 작성된 속성은 JavaScript의 객체 키가 된다. 컴포넌트 내에선, 이 속성을 변수로 읽어낼 수 있다. 다만 JavaScript 변수명엔 일정한 제약이 있다. 예를 들어, 이름에 하이픈(-)을 포함하거나 class와 같은 예약어를 사용하는 것은 안된다.
이를 위해, React는 HTML 및 SVG 파일의 속성을 카멜 케이스로 작성한다. 예를 들어 stroke-width 대신 strokeWidth를 사용한다. class는 예약어이기 때문에, React에선 className을 작성한다. (대응하는 DOM 프로퍼티가 유래되어진다.)
<img
src="https://i.imgur.com/yXOvdOSs.jpg"
alt="Hedy Lamarr"
className="photo"
/>
모든 항목은 React DOM 컴포넌트에 존재하는 속성 목록에서 확인할 수 있다. 잘못 작성할 경우에도 브라우저 콘솔창에 메시지와 어떻게 수정해야 할지에 대한 정보를 보여주기 때문에 걱정할 필요가 없다.
역사적 이유에 의해, aria-*와 data-* 속성은 HTML 속성과 같이 하이픈이 존재한다.
힌트: JSX 변환기를 사용한다.
선점한 마크업의 속성을 모두 바꿔 작성하는 것은 때로 귀찮을 수 있다. 선점한 HTML이나 SVG를 JSX로 변환할 경우 변환기를 사용하는 것을 추천한다. 변환기는 실용상 매우 도움되지만, 스스로 JSX 파일을 편하게 작성할 수 있도록, 무엇이 일어나는지 이해하는 것도 중요하다.
마지막 결과는 아래와 같다.
export default function TodoList() {
return (
<>
<h1>Hedy Lamarr's Todos</h1>
<img
src="https://i.imgur.com/yXOvdOSs.jpg"
alt="Hedy Lamarr"
className="photo"
/>
<ul>
<li>Invent new traffic lights</li>
<li>Rehearse a movie scene</li>
<li>Improve the spectrum technology</li>
</ul>
</>
);
}
정리
이것으로 JSX가 존재하는 이유와, 컴포넌트 내 사용 방법에 대해 이해할 수 있었다.
- 렌더링 로직과 마크업은 서로 관련되어있어, React에선 이것을 그룹화한다.
- JSX는 HTML과 비슷하지만 몇 개의 차이가 있다. 필요하다면 변환기를 사용한다.
- 에러 메시지를 보면, 대부분의 마크업 수정 방법에 대한 지시사항을 얻을 수 있다.