JSX는 흔히 개발자들이 알고 있는 XML과 유사한 내장형 구문이다. JSX가 포함된 구문을 아무런 처리 없이 그대로 실행하면 에러가 발생하며, 반드시 트랜스파일러를 거쳐야 비로소 자바스크립트 런타임이 이해할 수 있는 의미 있는 자바스크립트 코드로 변환된다. JSX의 설계 목적은 다양한 트랜스파일러에서 다양한 속성을 가진 트리 구조를 토큰화 해 ECMAScript로 변환하는데 초점을 두고 있다.
요약하자면 JSX는 자바스크립트 내부에서 표현하기 까다로웠던 XML 스타일의 트리 구문을 작성하는 데 많은 도움을 주는 새로운 문법이라고 볼 수 있다.
JSX는 기본적으로 JSXElement, JSXAttributes, JSXChildren, JSXStrings라는 4가지 컴포넌트를 기반으로 구성되어 있다.
JSX를 구성하는 가장 기본 요소로, HTML의 element와 비슷한 역할을 한다. JSXElement가 되기 위해서는 다음과 같은 형태 중 하나여야 한다.
JSXOpeningElement- 일반적으로 볼 수 있는 요소
- JSXOpeningElement로 시작했다면 후술할 JSXClosingElement가 동일한 요소로 같은 단계에서 선언되어 있어야 올바른 JSX 문법으로 간주된다.
- <JSXElemnt JSXAttributes(optional)>
JSXClosingElement- JSXOpeningElement가 종료됐음을 알리는 요소
- 반드시 JSXOpeningElement와 쌍으로 사용되어야 한다.
JSXSelfClosingElement- 요소가 시작되고 스스로 종료되는 형태
- 내부적으로 자식을 포함할 수 없다.
- <JSXElement JSXAttributes(optional) />
JSXFragment- 아무런 요소가 없는 형태
- JSXSelfClosingElement 형태를 띨 수는 없다.
- <>JSXChildren(optional)</>
JSXElement의 요소 이름으로 쓸 수 있는 것을 의미
JSXIdentifier- JSX 내부에서 사용할 수 있는 식별자
JSXNamespacedName- JSXIdentifier:JSXIdentifier의 조합
JSXMemberExpression- JSXIdentifier.JSXIdentifier의 조합
JSXElement에 부여할 수 있는 속성을 의미한다.
모든 경우에서 필수값이 아니고, 존재하지 않아도 에러가 나지 않는다.
function Example() {
return (
<Component attribute="hello"></Component>
<Component attribute=<div>hello</div>></Component>
);
}JSXElement의 자식 값을 나타낸다.
JSXChildren을 이루는 기본 단위
JSXChildren은 JSXChild를 0개 이상 가질 수 있다.
function Example() {
return (
<>{'{}'}</>
<>{(() => 'foo')()}</>
);
}HTML에서 사용 가능한 모든 문자열은 JSXStrings에서도 사용 가능하다.
자바스크립트와는 한가지 중요한 차이점이 있다.
\로 시작하는 이스케이프 문자 형태소 또한 제약없이 사용할 수 있다.
\는 자바스크립트에서 특수문자를 처리할 때 사용되므로 제약사항이 있지만, HTML에서는 아무런 제약 없이 사용할 수 있다.
//하나의 요소로 구성된 가장 단순한 형태
const ComponentA = <A>안녕하세요</A>;
//자식이 없이 SelfClosingTag로 닫혀있는 형태
const ComponentB = <A />;
//옵션을 { }와 전개 연산자로 넣음
const ComponentC = <A {...(required: true)} />;
//속성만 넣음
const ComponentD = <A required />;
//속성과 속성값을 넣음
const ComponentE = <A required={false} />;
//문자열은 작은 따옴표와 큰 따옴표 모두 가능
const ComponentF = (
<A>
<B text="리액트" />
</A>
);
//옵션의 값으로 JSXElement를 넣음
const ComponentG = (
<A>
<B optionalChildren={<>리액트</>} />
</A>
);
//여러개의 자식 포함
const ComponentH = (
<A>
리액트
<B text="리액트 2" />
</A>
);@babel/plugin-transform-react-jsx 플러그인은 JSX 구문을 자바스크립트가 이해할 수 있는 형태로 변환한다.
- JSX 코드
const ComponentA = <A required={true}>Hello World</A>;
const ComponentB = <>Hello World</>;
const ComponentC = (
<div>
<span>Hello World</span>
</div>
);- JSX 코드를
@babel/plugin-transform-react-jsx로 변환한 결과
'use strict’
var ComponentA =React.createElement(
A,
{
required: true,
},
'Hello World',
)
var ComponentB = React.createElement(React.Fragment, null, ’Hello World’)
var ComponentC = React.createElement(
’div’,
null,
React.createElement(’span’, null, ’Hello World'),
)- 리액트 17, 바벨 7.9.0 이후 버전에서 추가된 자동 런타임으로 트랜스파일한 결과
'use strict’
var _jsxRuntime = require (’custom-jsx-library/jsx-runtime')
var ComponentA = (0, _jsxRuntime.jsx)(A,
{
required: true,
children : 'Hello World' ,
})
var ComponentB = (0, _jsxRuntime.jsx)(_jsxRuntime.Fragment, {
children : 'Hello World’,
})
var ComponentC = (0, _jsxRuntime.jsx)('div’, {
children: (0, _jsxRuntime.jsx)(’span’, {
children: ’Hello World’
}),
})JSX 반환값이 결국 React.createElement로 귀결된다는 사실을 활용해 리팩터링할 수 있다.
- JSXNamespacedName
- JSXMemberExpression
JSX는 대부분의 경우 편리하고 간결하게 컴포넌트를 작성하는데 많은 도움을 주지만, 때에 따라서는 직접 createElement를 사용해 컴포넌트를 구성하는 편이 더 효율적일 수 있다.