본문 바로가기

FrontEnd/React

[React] JSX 구문 이해하기

 React.createElement 호출의 복잡성 문제

  React.createElement는 가상 DOM 객체를 만들어 주는 함수이지만 HTML요소가 부모/자식 관계로 구성되면 코드가 지나치게 복잡해지는 문제가 있다.

<ul>
	<li>
    	<a href="http://www.google.com">
        	<p>go to google</p>
        </a>
    </li>
</ul>

 

  이 코드를 React.createElement 호출로 구현해보자. 하지만 CE가 연속적으로 호출되면 해당 소스가 직관적으로 와닿지 않는다는 걸 알 수 있다.

import React from 'react'
import ReactDOM from 'react-dom/client'

const CE = React.createElement

const rootVirtualDOM = CE('ul', null, [
  CE('li', null, [
    CE('a', {href: 'http://google.com', target: '_blank'}, [
      CE('p', null, 'go to google')
    ])
  ])
])

const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement)
root.render(rootVirtualDOM)

 

  위와 같은 React.createElement의 복잡성을 해결하기 위해 자바스크립트 언어에 없는 JSX기능을 언어 확장(language extension)형태로 추가했다.

import ReactDOM from 'react-dom/client'
// JSX코드를 통해 createElement의 복잡성을 해소함.
const rootVirtualDOM = (
  <ul>
    <li>
      <a href="http://google.com" target="_blank">
        <p>go to Googlef</p>
      </a>
    </li>
  </ul>
)
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement)
root.render(rootVirtualDOM)

 

 JSX = Javascript + XML

  JSX는 'Javascript XML'의 줄임말로 XML 구문에 자바스크립트 코드를 결합해 사용하는 용도로 만들어진 구문이다.

 React.createElement 호출 코드를 간결하게 하려고 고안된 것이며 자바스크립트 언어를 확장하는 방식으로 구현되었다.

  •  웹 브라우저의 HTML 구문 분석기와 달리 JSX의 구문 분석기는 XML 규약을 엄격하게 준수해야 한다.
    <input type="text">   →  <input type="text" />
    <img src="some url">  →  <img src="some url" />
  • JSX 구문에서 중괄호의 의미
    XML에 자바스크립트 코드를 삽입하려면 중괄호{}를 사용하는 형태의 문법을 제공해 삽입한다.  중괄호 안의 자바스크립트 코드는 값만을 반환해야 한다.  return 없이 값을 반환하는 구문을 타입스크립트에서는 표현식이라고 한다.
    const hello = 'hello world!'
    <p>{hello}</p>  // 중괄호를 사용해 javascript를 jsx에 삽입한다.

 표현식과 실행문, 그리고 JSX

  표현식(expression)이란 return 키워드 없이 어떤 값을 반환하는 코드를 뜻한다.  1, true, 'Hello world!'처럼 값으로 칠 수 있는 것들을 의미한다.  1+1과 같은 코드 조각, 함수 호출로 반환되는 값 등 값이 될 수 있는 모든 것을 의미한다.  표현식과 대비되는 개념으로는 실행문(execution statement)이 있다.  실행문은 if, switch ~ case, for문 등을 의미한다.  즉, 그 자체로는 값이 아닌 것들을 의미한다.

 

 배열과 JSX 구문

  JSX구문은 단순화된 React.createElement 호출이므로 반환값은 가상DOM 객체이기 때문에 변수나 배열에 담을 수 있다.

 또한, JSX문에서 자식 컴포넌트가 여러 개일 경우 반드시 XML 작성 원칙을 준수해야 한다.  XML 문법에서 XML요소는 부모없이 존재할 수 없다.

import ReactDOM from 'react-dom/client'

const children = [
  <li>
    <a href="http://www.google.com" target="_blank">
      <p>go to Google</p>
    </a>
  </li>,
  <li>
    <a href="http://www.google.com" target="_blank">
      <p>go to Google</p>
    </a>
  </li>,
  <li>
    <a href="http://www.google.com" target="_blank">
      <p>go to Google</p>
    </a>
  </li>
]
// {children}는 부모 컴포넌트인 <ul>없이 {children} 형태로 존재할 수 없다.
const rootVirtualDOM = <ul>{children}</ul>

const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement)
root.render(rootVirtualDOM)

 

  • 데이터 배열을 컴포넌트 배열로 만들기
    import ReactDOM from 'react-dom/client'
    
    const children = [0, 1, 2].map((n: number) => <h3>Hello world! {n}</h3>)
    const rootVirtualDOM = <div>{children}</div>
    
    const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement)
    root.render(rootVirtualDOM)


     브라우저 상에서는 이렇게 key가 없다는 오류가 발생한다.  해당 오류를 제거하기 위해 key속성을 추가한다.
    React에서 key는 리스트의 각 항목을 식별하기 위한 고유한 값으로 사용되며, 렌더링 성능을 최적화하고 컴포넌트가 적절히 업데이트 되도록 돕는 역할을 한다.
    import ReactDOM from 'react-dom/client'
    import * as D from './data'
    const children = D.makeArray(10).map((notUsed, index) => (
      <div key={index}>
        <p>{D.randomId()}</p>
        <p>{D.randomName()}</p>
        <p>{D.randomJobTitle()}</p>
        <p>{D.randomSentence()}</p>
        <img src={D.randomAvatar()} width={100} height={100} />
      </div>
    ))
    const rootVirtualDOM = <div>{children}</div>
    
    const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement)
    root.render(rootVirtualDOM)