React - JSX
드디어 돌아온 CS
자바스크립트에 대해서 대략적으로 알아봤으니 다른 것도 공부하고 싶은 욕구가 생겼다. 그래서 리액트를 사용하는데 어떻게 돌아가는지는 알아야 하지 않겠나 싶은 생각에 무작정 책을 샀다. 생각보다 책이 많이 두꺼워서 놀랐고 글자밖에 없어서 더 놀랐다. 지금까지 코어 자바스크립트를 정리할때처럼 한 포스트에 한장씩 정리하기엔 내용이 많기에 조금씩 쪼개서 정리해보겠다.
JSX란?
리액트를 사용하다보면 JSX라는 단어를 무조건 봤을 것이다. 내가 아는 정도는 HTML을 직접 작성하지 않고 JS로 작성하는 기능이라고만 알고 있었기 때문에 정확하게 뭔지, 어떤 원리로 동작하는지 알아보겠다.
JSX는 페이스북에서 리액트를 개발하면서 소개한 새로운 구문으로 XML과 유사한 내장형 구문이다.
JSX는
JavaScript XML의 약자이다.
페이스북에서 독자적으로 개발했기 때문에 ECMAScript, 자바스크립트의 표준은 아니다. 그래서 자바스크립트 엔진이나 브라우저에서 독단적으로 사용이 불가능하다.
// Uncaught SyntaxError: Unexpected token '<' const Component = ( <div>test</div> )
JSX는 위와 같이 사용하는데 브라우저에서 실행하면 에러가 발생한다. 그래서 트랜스파일러를 거쳐 자바스크립트 런타임이 이해가능한 자바스크립트 코드로 변환시켜줘야한다. 그래서 아마 리액트를 사용해봤다면 처음에 필수적으로 babel을 설치했을 것이다. 이 babel이라는 트랜스파일러를 통해 JSX로 작성된 코드를 자바스크립트로 변환시켜주는 것이다.
그렇다고 JSX가 단순히 HTML과 XML을 자바스크립트로 표현하는 목적만 가진것은 아니다. JSX의 설계 목적은 트랜스파일러에서 다양한 속성을 가진 트리 구조를 토큰화해 ECMAScript로 변환하는데 초점을 두고 있다. 즉, JSX내부에 트리 구조로 표현하고 싶은 것을 작성하고 트랜스파일러를 통해 자바스크립트가 이해할 수 있는 코드로 변환하는 것이 주된 목적이다.
JSX의 구성과 소개
JSXElement
가장 기본적인 요소이다. HTML의 element와 비슷한 역할을 한다. 우리가 알고 있던 태그를 사용하는 방식과 거의 비슷하다.
<div>test</div> // 태그를 생성했다면 닫아야함 <Component/> // 스스로 종료되는 형태도 가능함 <>test</> //아무런 내용이 없는 태그, Fragment도 가능함
추가적으로 알아야하는 규칙이 있다. 리액트에서 사용할때 요소명은 대문자로 시작해야 컴포넌트로 사용이 가능하다.
function test(){ return <span>test</span> } //error export function App(){ return <test/> }
JSXElement에 명시된 표준은 아니지만 리액트 자체적으로 HTML의 태그와 JSX태그를 구분하기 위함이다. 그래서 위와 같은 컴포넌트를 사용하려고 한다면 컴포넌트가 아닌 HTML의 태그로 인식해 에러가 발생하는 것이다.
네이밍 규칙도 간단하게 알아보면
function Number(){ return<$></$> // 자바스크립트 식별자 규칙과 동일, $이나 _로 시작가능 } function Number(){ return<1></1> // 숫자로 시작 안됨 } function Spaced(){ return <foo:bar></foo:bar> // :를 통해서 두개의 식별자를 조합해 하나의 식별자로 사용 가능(2개까지 가능) } function Expression(){ return <foo.bar.baz></foo.bar.bax> // .를 통해서 두개의 식별자를 조합해 하나의 식별자로 사용 가능(여러개 가능) }
이미 알고 있는 규칙을 따라주면서 element를 만들어주면 된다.
JSXAttiributes
JSXElement에 부여하는 속성이다. 속성이기 때문에 아무런 속성이 없어도 에러가 나지 않는다. 기본적으로 속성은 키와 값으로 이루어서 표현한다. 키는 JSXAttributeName, 값은 JSXAttobuteValue라고 한다.
function Test(){ return<div option={option}>test</div> }
속성으로 할당 가능한 값은 다음중 하나를 만족해야 한다.
- 큰따옴표로 구성된 문자열
- 작은 따옴표로 구성된 문자열
- {AssignmentExpression} : 자바스크립트 전개 연사자와 같음, 자바스크립트에서 변수에 값을 넣을 수 있는 표현식
- JSXElement
마지막에 소개한 JSXElement를 할당하는 것을 코드로 보면
function Component({attribute}){ return<div>{attribute}</div> } function Test(){ return<div><Component attribute=<div>test<div> /></div> }
이렇게도 가능하다는 것이다. 리액트를 사용해봤다면 이런 방식보다 JSXElement를 {}로 감싸는 형태를 사용했을 것이다. 이건 문법적인 오류가 아닌 prettier의 규칙이다. 좀더 읽기 쉽도록 도와준다.
JSXChildren
JSXElement의 자식 값을 나타낸다. JSX는 트리구조를 가지기 때문에 부모와 자식 관계를 나타낼 수 있고 자식을 JSXChildren이라고 한다.
// (1) function Text(){ return <div>{'{}, <>'}</div> } // (2) function Function(){ return <div>{()=>'foo'}</div> // foo }
JSXChildren은 JSXChild로 이뤄져 있다. JSXChild는 JSXChildren의 기본 단위가 되고, 0개 이상 가질수 있다. 0개 이상이기 때문에 없어도 에러가 발생하지 않는다. JSXChild는 문자열, 다른 JSXElement, Fragment 모두 들어갈 수 있지만 예외 사항들을 위에 작성해봤다. 우선 문자열중 {, }, <, >은 사용이 안된다. 왜냐하면 기존 JSX문법과 혼동이 발생하기 때문이다. 그리고 두번째 예시처럼 {AssignmentExpression}와 같이 모든 표현식이 가능하다. 그래서 위와 같은 코드를 작성해도 정상적으로 동작한다.
JSXString
단어 그대로 JSX에서 사용하는 문자열이다. HTML와 JSX사이에 복사 붙여넣기가 쉽게 할 수있도록 설계되었다. 그래서 자바스크립트와 약간 다른점이 발생한다.
const string = '\' //error
자바스크립트에서 \은 특수문자를 처리할 때 사용하기 때문에 단독적으로 사용하지 못한다. 그래서 \\와 같은 방법을 사용해야하지만 HTML에서는 \로 시작가능하기 때문에 JSX에서도 문자열로 사용이 가능하다.
JSX에서 자바스크립트로 변환
이제 이렇게 작성한 JSX가 어떻게 변환되는지 알아보겠다. 우선 위에서 얘기했듯이 리액트에서 사용하는 babel/plugin-transform-react-jsx플러그인을 통해 알아보겠다.
cosnt ComponentA = <A required={true}>Hello world</A> const ComponentB = <>Hello world</> const ComponentC = ( <div> <span>Hello world</span> </div> )
이렇게 작성된 코드를 babel/plugin-transform-react-jsx플러그인을 사용해 변환시키면
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') )
이렇게 변환된다. 몇가지만 변환해 봤을때 확실한 것은 JSX를 React.createElement를 통해 각 요소들을 변환해주고 있다는 것을 알수가 있다. 그래서 이런 특성을 알고 있다면 조건부 렌더링을 할때에도 유용하게 사용이 가능하다.
import {createElement} from 'react' function TextOrHeading({ isHeading, children, }){ return createElement( isHeading ? 'h1' : 'span', {className: 'text'}, children, ) }
이렇게 하면 태그를 일일히 작성할 필요없이 태그를 생성할 수 있게 된다.
마무리
지금까지 리액트를 사용하면서 JSX가 뭔지는 알고 있었지만 세부적으로 어떻게 되어있는지까지 공부해본 적이 없다. 그냥 리액트에서 사용하는 문법정도이고 작성한 코드가 자바스크립트로 변환된다는 것만 알고 있었다. 이번 기회에 가장 기초를 알아가는 시간이 되어서 유의미하다. 물론 앞으로 가야할 길이 더 멀지만 천리길도 한걸음부터...
다음은 리액트에서 핵심적인 가상DOM에 대해서 알아보겠다. 진도는 욕심부리지 않고 조금씩 작성해보겠다.
개의 댓글
1
드디어 돌아온 CS
JSX란?
JSX의 구성과 소개
JSXElement
JSXAttiributes
JSXChildren
JSXString
JSX에서 자바스크립트로 변환
마무리