JSX

React์—์„œ UI ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ณด๋‹ค ์‰ฝ๊ฒŒ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋˜๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ + XML ํ™•์žฅ ๋ฌธ๋ฒ•์ด๋‹ค.

JSX ๋ฌธ๋ฒ•์ด ์‰ฌ์šด ์ด์œ ๋Š” ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์ž์—๊ฒŒ ๊ฐ€์žฅ ์นœ์ˆ™ํ•˜๊ณ  ์ง๊ด€์ ์ธ ๋งˆํฌ์—… ๊ตฌ์กฐ๋กœ ๋˜์–ด์žˆ๊ธฐ ๋–„๋ฌธ

JSX ๋ฌธ๋ฒ• ๊ทธ ์ž์ฒด๋กœ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์—”์ง„์ด๋‚˜ ๋ธŒ๋ผ์šฐ์ €์—์„œ ํ•ด์„ํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— Babel๊ณผ ๊ฐ™์€ ํŠธ๋žœ์ŠคํŒŒ์ผ๋Ÿฌ๋ฅผ ํ†ตํ•ด ์—”์ง„ ๋˜๋Š” ๋ธŒ๋ผ์šฐ์ €์—์„œ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋Š” ๋ฌธ๋ฒ• ์ฆ‰ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ๋กœ ๋‹ค์‹œ ๋ณ€ํ™˜ํ•˜๋Š” ๊ณผ์ •์ด ํ•„์š”ํ•˜๋‹ค.

JSX๋Š” HTML์ด ์•„๋‹Œ XML

XML
HTML

๋Œ€์†Œ๋ฌธ์ž ๊ตฌ๋ถ„

O

X

์ปค์Šคํ…€ ํƒœ๊ทธ

O

X

๋‹ซ๋Š” ํƒœ๊ทธ </> ํ•„์š”

O

X

  • JSX๋Š” HTML element ์™ธ ์ถ”๊ฐ€์ ์œผ๋กœ ์ปดํฌ๋„ŒํŠธ๋ฅผ ํƒœ๊ทธ๋กœ ์ •์˜ํ•˜์—ฌ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋‹ค.

  • React์—์„œ JSX๋Š” ๋Œ€๋ฌธ์ž โ†’ ์ปดํฌ๋„ŒํŠธ, ์†Œ๋ฌธ์ž โ†’ HTML element๋กœ ๋Œ€์†Œ๋ฌธ์ž๋ฅผ ๊ตฌ๋ถ„ํ•œ๋‹ค.

  • JSX๋Š” ๋‹ซ๋Š” ํƒœ๊ทธ๋ฅผ ๋ช…์‹œํ•ด์ค˜์•ผ ํ•œ๋‹ค.

JSX๋Š” React์—์„œ๋งŒ ์“ฐ์ด๋Š”๊ฑธ๊นŒ?

JSX๋Š” ๋ฆฌ์—‘ํŠธ์—์„œ๋งŒ ์‚ฌ์šฉ๋˜๋Š” ์ „์œ ๋ฌผ์ด ์•„๋‹Œ ๋‹ค๋ฅธ ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ฌธ๋ฒ•์ด๋‹ค.

  • Vue.js: ๊ธฐ๋ณธ์ ์œผ๋กœ ํ…œํ”Œ๋ฆฟ ๊ธฐ๋ฐ˜์˜ ๋ฌธ๋ฒ•์„ ์‚ฌ์šฉํ•˜์ง€๋งŒ JSX๋กœ๋„ Vue ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

  • ๊ทธ ์™ธ ์‚ฌ์šฉ๋˜๋Š” ํ”„๋ ˆ์ž„์›Œํฌ preact, ember.js, Hyperapp ๋“ฑ

  • ์ฆ‰, JSX๋ฌธ๋ฒ•์€ ํ•˜๋‚˜์˜ ํŠน์ • ์ฝ”๋“œ๋กœ๋งŒ ๋ณ€ํ™˜๋˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ ๊ฐ ํ”„๋ ˆ์ž„์›Œํฌ ๋งˆ๋‹ค ๋ณ€ํ™˜๋˜๋Š” ์ฝ”๋“œ๋Š” ๋ชจ๋‘ ๋‹ค๋ฅด๋‹ค.

JSX๋Š” Syntactic sugar

๋ฌธ๋ฒ•์  ์„คํƒ•(Syntactic sugar) ์ด๋ž€ ๋ฌธ๋ฒ•์  ๊ธฐ๋Šฅ์€ ๋™์ผํ•œ๋ฐ ๊ทธ๊ฒƒ์„ ์ฝ๋Š” ์‚ฌ๋žŒ ๋˜๋Š” ์ž‘์„ฑํ•˜๋Š” ์‚ฌ๋žŒ์ด ์ฝ”๋“œ๋ฅผ ๋ณด๋‹ค ์ง๊ด€์ ์ด๊ณ  ์ฝ๊ธฐ ์‰ฝ๊ฒŒ ๋””์ž์ธ ๋œ ๋ฌธ๋ฒ•์ด๋‹ค.

JSX๋Š” ์‰ฌ์šด ๋งˆํฌ์—… ๊ตฌ์กฐ๋กœ ์ž‘์„ฑ ๋˜๋ฉฐ ํŠน์ • ๊ธฐ๋Šฅ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ์ฝ”๋“œ๋กœ ๋ณ€ํ™˜ ๋˜๊ธฐ ๋–„๋ฌธ์— ๋™์ผํ•œ ๊ธฐ๋Šฅ์„ ๋ณด๋‹ค ์‰ฝ๊ฒŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋Š” Syntactic sugar์ด๋‹ค.

jsx๋Š” Syntactic sugar ์ด๊ธฐ์— jsx๋กœ ํ•  ์ˆ˜ ์žˆ๋Š” ๋ชจ๋“  ๊ฒƒ์€ ์ˆœ์ˆ˜ Javascript๋กœ๋„ ํ•  ์ˆ˜ ์žˆ๋‹ค.

React๋Š” JSX ๋ฌธ๋ฒ•์„ React.createElement(tag, props, ...children) ํ•จ์ˆ˜๋กœ ๋ณ€ํ™˜์‹œํ‚จ๋‹ค.

React.createElement

๋ฆฌ์—‘ํŠธ๋Š” ํšจ์œจ์ ์ธ ๋ Œ๋”๋ง์„ ์œ„ํ•ด ์‹ค์ œ ๋”๊ณผ ๊ฐ™์€ ๊ตฌ์กฐ์ธ ๊ฐ€์ƒ ๋”(Virtual DOM)์„ ์‚ฌ์šฉํ•œ๋‹ค. ์ด ๊ฐ€์ƒ ๋”์„ ๊ฐ„๋‹จํ•œ ๊ฐ์ฒด ๊ตฌ์กฐ๋กœ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ๋ฆฌ์—‘ํŠธ์—์„œ ์ œ๊ณตํ•˜๋Š” ํ—ฌํผ ํ•จ์ˆ˜

DOM API์—์„œ ๋” ํŠธ๋ฆฌ๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ์š”์†Œ๋ฅผ ๋งŒ๋“œ๋Š” document.createElement()์™€ ๋น„์Šทํ•œ ๋งฅ๋ฝ์œผ๋กœ ๋ฆฌ์—‘ํŠธ์—์„œ ์‚ฌ์šฉํ•˜๋Š” Virtual DOM ํŠธ๋ฆฌ๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ์š”์†Œ React Element๋ฅผ ๋งŒ๋“œ๋Š” ํ•จ์ˆ˜์ด๋‹ค.

React๋Š” JSX ๋ฌธ๋ฒ•์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ ๋„ createElement(tag, props, ...children)๋งŒ์„ ์‚ฌ์šฉํ•˜์—ฌ ์•ฑ์„ ๋งŒ๋“ค ์ˆ˜๋„ ์žˆ๋‹ค.

์ผ๋ถ€ ์กฐ๊ฐ์ด ์ „์ฒด์™€ ๋น„์Šทํ•œ ํ”„๋ž™ํƒˆ(fractal)๊ตฌ์กฐ์ธ๋ฐ ์–ด์ฐŒ๋ณด๋ฉด ๋‹น์—ฐํ•œ๋ฐ, DOM์ด Tree ๊ตฌ์กฐ์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

DOM API๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค๋Š” ์ฝ”๋“œ๋Ÿ‰์ด ์ค„์—ˆ์œผ๋‚˜ ์—ฌ์ „ํžˆ ์ง๊ด€์ ์ด์ง€ ์•Š์•„ UI๊ตฌ์กฐ๋ฅผ ํŒŒ์•…ํ•˜๊ธฐ ํž˜๋“ค๋‹ค.

const vdom = createElement(
  'p',
  {},
  createElement('h1', {}, 'react awesome'),
  createElement(
    'ul',
    {},
    createElement('li', { style: 'color: red' }, 'first item'),
    createElement('li', { style: 'color: orange' }, 'second item'),
    createElement('li', { style: 'color: green' }, 'third item')
  )
);

jsx๋ฅผ React.createElement()๋กœ ๋ณ€ํ™˜

jsx ๋ฌธ๋ฒ•์„ ํ†ตํ•ด ๋‚ด๋ถ€์ ์œผ๋กœ React.createElement()๊ฐ€ ๋™์ž‘ํ•˜๋Š” ์‹์œผ๋กœ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด์„œ๋Š” ํŠธ๋žœ์ŠคํŒŒ์ผ๋Ÿฌ์˜ ๋„์›€์ด ํ•„์š”ํ•˜๋‹ค.

๊ฐ€์žฅ ๋Œ€ํ‘œ์ ์œผ๋กœ ์“ฐ์ด๋Š” Babel์˜ ๊ฒฝ์šฐ @babel/plugin-transform-react-jsx๊ฐ€ ํ•ด๋‹น ํ•จ์ˆ˜๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ์—ญํ• ์„ ํ•œ๋‹ค. ๋ณ€ํ™˜๋˜๋Š” ์ฝ”๋“œ ํ™•์ธํ•˜๊ธฐ

@babel/preset-react vs @babel/plugin-transform-react-jsx

ํ”„๋ฆฌ์…‹(preset): ๋ชฉ์ ์— ๋งž๊ฒŒ ์—ฌ๋Ÿฌ๊ฐ€์ง€ ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ๋ฌถ์–ด ๋†“์€ ์„ธํŠธ

ํ”Œ๋Ÿฌ๊ทธ์ธ(plugin): ์ฝ”๋“œ๋ฅผ ๋ณ€ํ™˜ํ•˜๋Š” ์—ญํ• ์„ ์ˆ˜ํ–‰

@babel/preset-react โ†’ React ์•ฑ์—์„œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ๋กœ ๋ณ€ํ™˜ํ•  ๋•Œ ์‚ฌ์šฉ๋˜๋Š” ํ”Œ๋Ÿฌ๊ทธ์ธ๋“ค์˜ ์ง‘ํ•ฉ

@babel/plugin-transform-react-jsx โ†’ jsx ๋ฌธ๋ฒ•์„ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ์—ญํ• 

์‚ฌ์šฉ์ž ์ปดํฌ๋„ŒํŠธ

UI์กฐ๊ฐ์„ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ๋ชจ๋“ˆํ™” ํ•˜๋“ฏ์ด ์กฐ์งํ™”ํ•  ์ˆ˜ ์žˆ๋‹ค.

  • ๋ชจ๋“ˆํ™”๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค๋Š” ๊ฒƒ์€ ์–ธ์ œ๋“  ํ•„์š”ํ• ๋•Œ ์žฌ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•˜๋‹ค๋Š” ์–˜๊ธฐ

  • html ํƒœ๊ทธ์™€ ๋‹ฌ๋ฆฌ ์ด๋ฆ„์„ ๋ถ™์—ฌ ์ข€ ๋” ์˜๋ฏธ๊ฐ€ ๋ช…ํ™•ํ•œ UI ํ˜•ํƒœ๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋Š” ์žฅ์ ์ด ์žˆ๋‹ค.

React.createElement() ํ•จ์ˆ˜์—์„œ ์ฒซ๋ฒˆ์งธ ์ธ์ž๊ฐ’์œผ๋กœ ๋Œ€๋ฌธ์ž๊ฐ€ ๋“ค์–ด์˜ค๋ฉด ์ฆ‰, jsx ๋ฌธ๋ฒ•์˜ ํƒœ๊ทธ ์ด๋ฆ„์ด ๋Œ€๋ฌธ์ž๋กœ ์‹œ์ž‘๋˜๋ฉด ๋ฌธ์ž์—ด๋กœ ์ทจ๊ธ‰ํ•˜์ง€ ์•Š๊ณ  ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๊ฐ’(ํ•จ์ˆ˜, ํด๋ž˜์Šค)์œผ๋กœ ์ทจ๊ธ‰๋œ๋‹ค.

const Hello = () => <h1>Hello</h1>;
const hello = () => <h1>hello</h1>;
const App = (
  <p>
    <Hello></Hello>
    <hello></hello>
  </p>
);

// @babel/preset-react ๋ณ€ํ™˜ ํ›„
const Hello = () => React.createElement('h1', null, 'Hello');
const hello = () => React.createElement('h1', null, 'hello');
const App = React.createElement(
  'p',
  null,
  React.createElement(Hello, null), // ๋Œ€๋ฌธ์ž๋Š” ๊ฐ’์œผ๋กœ ์ทจ๊ธ‰
  React.createElement('hello', null) // ์†Œ๋ฌธ์ž๋Š” ๋ฌธ์ž์—ด๋กœ ์ทจ๊ธ‰
);

์ปดํฌ๋„ŒํŠธ๋Š” ๋ฐ˜๋“œ์‹œ createElement() ์˜ ๊ฒฐ๊ณผ๊ฐ’ ์ฆ‰, jsx๋ฌธ์„ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•œ๋‹ค. ์ปดํฌ๋„ŒํŠธ๋Š” createElement(tag, props, ...children) ์ธ์ž ์ค‘ children ์ธ์ž๋ฅผ props์— ํ•ฉํ•ด์„œ ์ž…๋ ฅ๋ฐ›๊ฒŒ ๋œ๋‹ค.

export function createElement(tag, props, ...children) {
  if (typeof tag === 'function') {
    return tag({
      ...props,
      children: children.length === 1 ? children[0] : children,
    });
  } else {
    return {
      tag,
      props: props ?? {},
      children,
    };
  }
}

React17 new Trasnform jsx

React17 ์ด์ „์—๋Š” jsx ๊ตฌ๋ฌธ์„ ์‚ฌ์šฉํ•  ๋•Œ import React from 'react'๋ฅผ ํฌํ•จ ํ•ด์•ผํ•˜๋Š” ๊ตฌ์กฐ์  ์ œ์•ฝ์‚ฌํ•ญ์ด ์žˆ์—ˆ๋Š”๋ฐ ๊ทธ ์ด์œ ๊ฐ€ ๋‚ด๋ถ€์ ์œผ๋กœ React.createElement() ๋กœ ๋ณ€ํ™˜์ด ๋˜๋ฉด์„œ React๋ฅผ ์ฐธ์กฐํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. -> React17์—์„œ ์ƒˆ๋กญ๊ฒŒ ๋ณ€๊ฒฝ๋œ ๊ธฐ๋Šฅ๋“ค ์ค‘ jsx๋ฅผ ๋ณ€ํ™˜ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์ถ”๊ฐ€๋˜์—ˆ๋Š”๋ฐ ๊ทธ๋กœ ์ธํ•ด ๋” ์ด์ƒ React๋ฅผ import ์„ ์–ธํ•˜์ง€ ์•Š๊ณ  ์ž‘์—…์ด ๊ฐ€๋Šฅํ•ด์กŒ๋‹ค. ์ž์„ธํžˆ ์‚ดํŽด๋ณด๊ธฐ

const App = () => {
  return (
    <div className='react'>
      <Component title='awesome' />
    </div>
  );
};

// createElement()
const App = () => {
  return React.createElement(
    'div',
    {
      className: 'react',
    },
    React.createElement(Component, {
      title: 'awesome',
    })
  );
};

// react17 new Transform jsx
import { jsx as _jsx } from 'react/jsx-runtime'; // ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์ž๋™์œผ๋กœ ์ž„ํฌํŠธํ•ด์ค€๋‹ค.
const App = () => {
  return _jsx('div', {
    className: 'react',
    children: _jsx(Component, {
      title: 'awesome',
    }),
  });
};

Last updated