JSX 좀 더 알아보기

상현·2024년 5월 13일
1
post-thumbnail

JSX는 리액트가 등장하면서 페이스북에서 소개한 새로운 구문이다. 그러나 반드시 리액트에서만 사용할 수 있는 것은 아니다. JSX는 XML과 유사한 내장형 구문이며, 리액트에 종속되어 있지 않은 독자적인 문법으로 보는 것이 옳다.

JSX가 포함된 코드를 아무런 처리 없이 그대로 실행하면 에러가 발생한다. JSX는 자바스크립트 표준이 아닌 페이스북이 만든 문법이기에 반드시 트랜스파일러를 거쳐야 자바스크립트 런타임이 이해할 수 있는 코드로 변환된다.

1. JSX의 정의

JSX는 JSXElement, JSXAtributes, JSXChildren, JSXStrings라는 4가지 컴포넌트를 기반으로 구성돼 있다.

JSXElement

JSX를 구성하는 가장 기본 요소이며 HTML의 element와 비슷한 역할을 한다. 다음과 같은 형태 중 하나여야 한다.

  • JSXOpeningElement: 여는 태그로 JSXClosingElement와 같이 쌍으로 사용되어야 한다.
    • <JSXElement >
  • JSXClosingElement: 닫는 태그로 JSXOpeningElemen와 같이 쌍으로 사용되어야 한다.
    • </JSXElement>
  • JSXSelfClosingElement: 요소가 스스로 시작되고, 닫히는 태그다. 내부적으로 자식을 포함할 수 없는 형태다.
    • <JSXElement />
  • JSXFragment: 아무런 요소가 없는 형태다
    • <></>

JSXElementName

JSXElementNameJSXElement의 요소 이름으로 쓸 수 있는 것을 의미한다.

  • JSXIdentifier: JSX 내부에서 사용할 수 있는 식별자를 의미한다.
    function Valid() {
    	return <$></$>
    }
  • JSXNamespaceName: :을 통해 JSXIdentifier를 이어주는 것도 하나의 식별자로 취급된다. 두 개 이상은 안된다.
    function Valid() {
    	return <foo:bar></foo:bar>
    }
  • JSXMemberExpression: .을 통해 JSXIdentifier를 이어주는 것도 하나의 식별자로 취급된다. JSXNamespaceName과 달리 여러 개를 이을 수 있다.
    function Valid() {
    	return <foo.bar.baz></foo.bar.baz>
    }

JSXAttributes

JSXElement에 부여할 수 있는 속성을 의미한다.

JSXChildren

JSXElement의 자식을 나타낸다. JSX는 속성을 가진 트리 구조를 나타내기 위해 만들어졌기 때문에 부모와 자식 관계를 나타낼 수 있다.

JSXStrings

HTML에서 사용 가능한 문자열은 모두 JSXStrings에서도 사용 가능하다. 이는 개발자가 HTML의 내용을 손쉽게 JSX로 가져올 수 있도록 설계된 부분이다.

2. JSX 예제

위에서 소개한 4가지 요소를 조합해 JSX를 만들어 보자.

// 하나의 요소로 구성된 가장 단순한 형태
const ComponentA = <A>Component 1</A>

// Self Closing
const ComponentB = <A />

// 옵션을 { } 와 전개 연산자로 넣을 수 있다.
const ComponentC = <A {...{isValid: true}} />

// 속성만 넣을 수 있다
const ComponentD = <A required />

// 속성과 속성 값을 넣을 수 있다
const ComponentE = <A required={false} />

const ComponentF = (
	<A>
		{/* 문자열은 따옴표, 큰따옴표, 백틱 모두 가능하다. */}
		<B text="리액트" />
		{/* 여러 개의 자식도 포함할 수 있다. */}
		<C />
		{/* 옵션의 값으로 JSXElement를 넣을 수 있다. */}
		<D child={<C />} />
	</A>
)

3. JSX가 자바스크립트로 변환 되는 방법

리액트에서 JSX를 변환할 때는 @bable/plugin-transform-react-jsx 플러그인을 통해 변환한다.

다음과 같은 JSX 코드가 어떻게 변하는지 보자.

const ComponentA = <A required={true}>Hello World</A>
const ComponentB = <>Hello World</>
const ComponentC = (
<div>
	<span>hello world</span>
</div>
)

다음과 같이 변환된다.

'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, _isxRuntime.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',
	5),
})

결과물에는 다음과 같은 공통점이 있다.

  • JSXElement를 첫 번째 인수로 선언해 요소를 정의한다.
  • 옵셔널인 JSXChildren, JSXAttributes, JSXStrings는 이후 인수로 넘겨주어 처리한다.

JSX 반환값은 결국 React.createElement로 귀결된다. 이 점을 활용하면 아래와 같이 중복 코드를 간결하게 처리할 수 있다.

// props 여부에 따라 children 요소만 달라지는 경우 불필요한 코드 중복이 일어난다.
function TextOrHeading({isHeading, children}) {
	return isHeading ? ( <h1 className="text">{children}</h1> 
	) : (
		<span className="text">{children}</span>
		)
}

// 다음과 같이 처리할 수도 있다.
import { createElement } from 'react'

function TextOrHeading({isHeading, children) {
	return createElement(
		isHeading ? 'h1' : 'span',
		{ className: 'text' },
		children,
	)
}

참조: 모던 리액트 Deep Dive 2장

profile
프론트엔드 개발자 블로그 이전 => https://shdev.blog/

0개의 댓글