JSX

Keyword

  1. JSX

  2. React Element

  3. Virtual DOM

    • 3-1 ์žฌ์กฐ์ •(Reconciliation)

  4. ์„ ์–ธ์  API


1. JSX

JSX๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ํ™•์žฅ๋œ ๋ฌธ๋ฒ•์œผ๋กœ ์—ด๋ฆฐ ํƒœ๊ทธ ๋‹ซํžŒ ํƒœ๊ทธ๋กœ ๊ตฌ์„ฑ๋œ XML ๋ฌธ๋ฒ•์„ ๋”ฐ๋ฅด๋ฉฐ HTML ๋ฌธ์„œ์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

Babel ํŠธ๋žœ์ŠคํŒŒ์ผ๋Ÿฌ

  • Babel์ด JSX๋ฌธ๋ฒ•์„ React.createElement(components, props, โ€ฆchildren) ํ•จ์ˆ˜๋กœ ํŠธ๋žœ์ŠคํŒŒ์ผ๋งํ•˜์—ฌ ๋ฌธ๋ฒ•์  ์„คํƒ•์„ ์ œ๊ณตํ•œ๋‹ค.

๋ฌธ๋ฒ•์  ์„คํƒ• ์ฝ๋Š” ์‚ฌ๋žŒ ๋˜๋Š” ์‚ฌ์šฉํ•˜๋Š” ์‚ฌ๋žŒ์—๊ฒŒ ํŽธ์˜๋ฅผ ์œ„ํ•ด ๋””์ž์ธ๋œ ๋ฌธ๋ฒ•์œผ๋กœ ๋ชจ๋“  ์ƒํ™ฉ์—์„œ ์ ํ•ฉํ•˜์ง€๋Š” ์•Š์ง€๋งŒ, ์ž‘์„ฑ์ž์˜ ์˜๋„๋ฅผ ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ๋Š” ์ƒํ™ฉ์— ์‚ฌ์šฉ์‹œ ์ง๊ด€์ ์ธ ๋ฌธ๋ฒ•์œผ๋กœ ๊ฐ€๋…์„ฑ์„ ๋†’์ธ๋‹ค. ex) ์‚ผํ•ญ์—ฐ์‚ฐ์ž, nullish ๋ณ‘ํ•ฉ ์—ฐ์‚ฐ์ž ๋“ฑ

  • React๋Š” ํ•ด๋‹น ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด React element ํŠธ๋ฆฌ๋ฅผ ๊ฐฑ์‹ ํ•œ๋‹ค.

  • JSX๋กœ ํ•  ์ˆ˜ ์žˆ๋Š” ๋ชจ๋“  ๊ฒƒ์€ Vanilla JS๋กœ๋„ ๊ฐ€๋Šฅํ•˜๋‹ค.

์ฝ”๋“œ ์˜ˆ์‹œ

<div className="test">
  <p>Hello, world!</p>
  <Button type="submit">Send</Button>
<div>

// ๋ณ€ํ™˜ ๊ฒฐ๊ณผ
React.createElement(
  "div",
  { className: "test" },
  React.createElement("p", null, "Hello, world!"),
  React.createElement(Button, { type: "submit" }, "Send")
);

์œ„์˜ ์ฝ”๋“œ์—์„œ ๋งŒ์•ฝ div ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ์ œ๊ฑฐํ•œ๋‹ค๋ฉด?

  // ์—๋Ÿฌ ๋ฐœ์ƒ
  <p>Hello, world!</p>
  <Button type="submit">Send</Button>

์ธ์ ‘ํ•œ JSX element๋Š” ๋‘˜๋Ÿฌ์‹ธ๋Š” ํƒœ๊ทธ๋กœ ๋ฌถ์–ด์•ผ ํ•œ๋‹ค๋Š” ์—๋Ÿฌ๋ฉ”์‹œ์ง€๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. ๋งˆ์น˜ ๋ฌธ์žฅ์„ ์„ธ๋ฏธ์ฝœ๋ก (;)์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ํ•œ ์ค„์— ์—ฐ์†์ ์œผ๋กœ ์ž…๋ ฅํ–ˆ์„ ๊ฒฝ์šฐ์™€ ๊ฐ™์€ ์…ˆ์ด๋‹ค. ex) add(1, 2) add(3, 4) => Missing semicolon error


2. React Element

React์—์„œ UI๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ์ตœ์†Œ ๋‹จ์œ„ React Element, ์ผ๋ฐ˜์ ์œผ๋กœ JSX๋กœ ํ‘œํ˜„๋œ๋‹ค. JSX ๋ฌธ๋ฒ•์€ ์„ ์–ธ์  API๋ฅผ ์ œ๊ณตํ•ด ์œ ์ง€๋ณด์ˆ˜ ๊ฐ€๋Šฅํ•˜๊ณ  ๊ฐœ๋ฐœ ์ƒ์‚ฐ์„ฑ์„ ์ฆ๊ฐ€์‹œํ‚ค์ง€๋งŒ, ๊ณต์‹๋ฌธ์„œ๋Š” React์—์„œ JSX๊ฐ€ ํ•„์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ๊ณ  ์„ค๋ช…ํ•œ๋‹ค.

์™œ ํ•„์ˆ˜๊ฐ€ ์•„๋‹Œ๊ฐ€?

์œ„์˜ JSX์—์„œ ์„ค๋ช…ํ•œ ๊ฒƒ ์ฒ˜๋Ÿผ Babel, swc์™€ ๊ฐ™์€ ํˆด์ด JSX ๋ฌธ๋ฒ•์„ React.createElement ํ•จ์ˆ˜๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ๊ฒƒ์ผ ๋ฟ์ด๋‹ค. (document.createElement ํ•จ์ˆ˜๊ฐ€ ๋™์ž‘ํ•˜๋Š” ๊ฒƒ ์ฒ˜๋Ÿผ!)

React automatic runtime

React 17๋ถ€ํ„ฐ automatic runtime์ด ๋„์ž…๋˜์—ˆ๋Š”๋ฐ, ๋” ์ด์ƒ import React from 'react'; ๊ตฌ๋ฌธ์„ ์ž…๋ ฅํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค. ์ด์ „์—๋Š” JSX๊ฐ€ React.createElement() ํ•จ์ˆ˜๋กœ ์ปดํŒŒ์ผ ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ํ•ด๋‹น import ๊ตฌ๋ฌธ์ด scope์•ˆ์— ์žˆ์–ด์•ผ ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

classic runtime

import React from 'react';

function App() {
  return <h1>Hello World</h1>;
}

import React from 'react';

function App() {
  return React.createElement('h1', null, 'Hello world');
}

automatic runtime

function App() {
  return <h1>Hello World</h1>;
}

import {jsx as _jsx} from 'react/jsx-runtime';

function App() {
  return _jsx('h1', { children: 'Hello world' });
}

์ฝ”๋“œ ๋ณ€ํ™˜ ์‹œ import {jsx as _jsx} from 'react/jsx-runtime'; import ๊ตฌ๋ฌธ์ด ์ถ”๊ฐ€๋œ๋‹ค.


3. Virtual DOM

Virtual DOM์€ ๋ฆฌ์•กํŠธ๊ฐ€ DOM์„ ์ถ”์ƒํ™”, ๊ฐ€์ƒ์ ์œผ๋กœ ํ‘œํ˜„ํ•ด ๋ฉ”๋ชจ๋ฆฌ์— ์ €์žฅํ•˜๊ณ , ReactDOM๊ณผ ๊ฐ™์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ์˜ํ•ด Real DOM๊ณผ ๋™๊ธฐํ™”ํ•˜๋Š” ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๊ฐœ๋…์ด๋‹ค.

ํ˜น์ž: VDOM์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ๋น ๋ฅด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค! (X)

๋ฆฌ์•กํŠธํŒ€ ๊ฐœ๋ฐœ์ž Dan Abramov์˜ ๋‹ต๋ณ€: ํ˜„์‹ค์€ ์œ ์ง€๋ณด์ˆ˜ ๊ฐ€๋Šฅํ•œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๋Œ€๋ถ€๋ถ„์˜ ์‚ฌ๋ก€์—์„  ์ถฉ๋ถ„ํžˆ ๋น ๋ฅด๋‹ค.

maiatainable

Vanilla JS๋กœ DOM element๋ฅผ ์ง์ ‘ ์…€๋ ‰ํŠธํ•ด ๊ฐ€๊ณตํ•˜๋Š” ๊ฒƒ์ด ๊ณผ์—ฐ ์œ ์ง€๋ณด์ˆ˜์— ์šฉ์ดํ• ๊นŒ?

React๋Š” ์„ ์–ธ์  API๋ฅผ ํ†ตํ•ด ๊ฐœ๋ฐœ์ž๊ฐ€ ์›ํ•˜๋Š” UI๋ฅผ ์ง์ ‘ ๋ช…๋ นํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ, ์›ํ•˜๋Š” ์ƒํƒœ๋ฅผ ์„ ์–ธ์ ์œผ๋กœ ํ”„๋กœ๊ทธ๋ž˜๋ฐํ•ด React๊ฐ€ ์ž๋™์œผ๋กœ UI๋ฅผ ์—…๋ฐ์ดํŠธํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฏ€๋กœ ์œ ์ง€๋ณด์ˆ˜์— ์šฉ์ดํ•˜๋‹ค.

Fast enough

์žฌ์กฐ์ •(Reconciliation) ์„ ํ†ตํ•ด ๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ์—” ์ถฉ๋ถ„ํžˆ ๋น ๋ฅด๋‹ค.

3-1 ์žฌ์กฐ์ •(Reconciliation)

ํ•˜๋‚˜์˜ ํŠธ๋ฆฌ๋ฅผ ๊ฐ€์ง€๊ณ  ๋‹ค๋ฅธ ํŠธ๋ฆฌ๋กœ ๋ณ€ํ™˜ํ•˜๊ธฐ ์œ„ํ•œ ์ตœ์†Œํ•œ์˜ ์—ฐ์‚ฐ ์ˆ˜๋ฅผ ๊ตฌํ•˜๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ O(n3)์˜ ์‹œ๊ฐ„ ๋ณต์žก๋„๋ฅผ ๊ฐ–๊ธฐ ๋•Œ๋ฌธ์— ์—ฐ์‚ฐ ๋น„์šฉ์ด ๋„ˆ๋ฌด ๋†’๋‹ค. React๋Š” ๋‘ ๊ฐ€์ง€ ๊ฐ€์ •์„ ๊ธฐ๋ฐ˜์œผ๋กœ O(n) ๋ณต์žก๋„์˜ ํœด๋ฆฌ์Šคํ‹ฑ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๊ตฌํ˜„ํ–ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ํœด๋ฆฌ์Šคํ‹ฑ์ด๋ž€ ์ค‘์š”ํ•˜์ง€ ์•Š์€ ๋ถ€๋ถ„์€ ์ œ์™ธํ•˜๊ณ  ์ค‘์š”ํ•œ ๋ถ€๋ถ„๋งŒ์„ ๊ณ ๋ คํ•ด์„œ ์ตœ์ ์˜ ๊ฐ’์„ ์ฐพ์•„๋‚ด์ž๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.

  1. ์„œ๋กœ ๋‹ค๋ฅธ ํƒ€์ž…์˜ ๋‘ ์—˜๋ฆฌ๋จผํŠธ๋Š” ์„œ๋กœ ๋‹ค๋ฅธ ํŠธ๋ฆฌ๋ฅผ ๋งŒ๋“ค์–ด๋‚ธ๋‹ค.

  2. ๊ฐœ๋ฐœ์ž๊ฐ€ key prop์„ ํ†ตํ•ด, ์—ฌ๋Ÿฌ ๋ Œ๋”๋ง ์‚ฌ์ด(๋ฐฐ์—ด์˜ ์—˜๋ฆฌ๋จผํŠธ ๋ Œ๋”๋ง)์—์„œ ์–ด๋–ค ์ž์‹ ์—˜๋ฆฌ๋จผํŠธ๊ฐ€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์•„์•ผ ํ• ์ง€ ํ‘œ์‹œํ•ด ์ค„ ์ˆ˜ ์žˆ๋‹ค.

๋น„๊ต(Diffing) ์•Œ๊ณ ๋ฆฌ์ฆ˜

Diffing ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ Reconciliation ๊ณผ์ •์—์„œ ์ด์ „ ์ƒํƒœ์™€ ์ƒˆ๋กœ์šด ์ƒํƒœ๋ฅผ ๋น„๊ตํ•˜์—ฌ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ์ฐพ์•„๋‚ด๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด๋‹ค. ๋‘ ๊ฐœ์˜ ํŠธ๋ฆฌ๋ฅผ ๋น„๊ตํ•  ๋•Œ, ๋ฆฌ์•กํŠธ๋Š” DOM Tree์˜ ๋™์ผ ๋ ˆ๋ฒจ/๊ณ„์ธต๋ผ๋ฆฌ level-by-level ๋กœ ํƒ์ƒ‰ํ•œ๋‹ค. ํ•ด๋‹น ์•„์ด๋””์–ด๊ฐ€ ํœด๋ฆฌ์Šคํ‹ฑ ์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ ์ค‘์š”ํ•œ ๋ถ€๋ถ„์„ ๊ณ ๋ คํ•˜๋Š” ๊ฒƒ์ด๋‹ค!

1-1. ์—˜๋ฆฌ๋จผํŠธ์˜ ํƒ€์ž…์ด ๋‹ค๋ฅธ ๊ฒฝ์šฐ

๋‘ ๋ฃจํŠธ ์—˜๋ฆฌ๋จผํŠธ์˜ ํƒ€์ž…์ด ๋‹ค๋ฅด๋ฉด, React๋Š” ์ด์ „ ํŠธ๋ฆฌ๋ฅผ ๋ฒ„๋ฆฌ๊ณ  ์™„์ „ํžˆ ์ƒˆ๋กœ์šด ํŠธ๋ฆฌ๋ฅผ ๊ตฌ์ถ•ํ•œ๋‹ค.

๋ฃจํŠธ ์—˜๋ฆฌ๋จผํŠธ๋ผ๋Š” ๊ฒƒ์ด ํŠธ๋ฆฌ์˜ ํ”„๋ ‰ํƒˆ ๊ตฌ์กฐ์  ๊ด€์ ์œผ๋กœ ํŠน์ • ์ปดํฌ๋„ŒํŠธ์—์„œ์˜ ๋ฃจํŠธ ์—˜๋ฆฌ๋จผํŠธ ๋˜ํ•œ ์ ์šฉ๋˜๋Š” ์˜๋ฏธ์ธ ๊ฒƒ ๊ฐ™๋‹ค. ๊ทธ๋ž˜์„œ ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ ํ˜น์€ ์—˜๋ฆฌ๋จผํŠธ์˜ ํƒ€์ž…์ด ๋‹ค๋ฅด๋‹ค๋ฉด ์ž์‹์„ ์ˆœํšŒํ•  ํ•„์š”์—†์ด ํ•ด๋‹น ๋…ธ๋“œ๋ฅผ ํฌํ•จํ•œ ์ž์‹ ๋…ธ๋“œ๋ฅผ ์ƒˆ๋กœ์šด Virtual DOM์œผ๋กœ ๋Œ€์ฒดํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

1-2. ์—˜๋ฆฌ๋จผํŠธ์˜ ํƒ€์ž…์ด ๊ฐ™์€ ๊ฒฝ์šฐ

React๋Š” ๋‘ ์—˜๋ฆฌ๋จผํŠธ์˜ ์†์„ฑ์„ ํ™•์ธํ•˜์—ฌ, ๋™์ผํ•œ ์†์„ฑ์˜ ๋‚ด์šฉ์€ ์œ ์ง€ํ•˜๊ณ  ๋ณ€๊ฒฝ๋œ ์†์„ฑ๋งŒ ๊ฐฑ์‹ ํ•œ๋‹ค.

// className ์†์„ฑ๋งŒ ์ˆ˜์ •
<div className="before" title="stuff" />
<div className="after" title="stuff" />

// style์˜ color ์†์„ฑ๋งŒ ์ˆ˜์ • 
<div style={{color: 'red', fontWeight: 'bold'}} />
<div style={{color: 'green', fontWeight: 'bold'}} />

2-1. ์ž์‹์— ๋Œ€ํ•œ ์žฌ๊ท€์  ์ฒ˜๋ฆฌ

๋ฐฐ์—ด์˜ ๋งจ ๋์— ์—˜๋ฆฌ๋จผํŠธ๊ฐ€ ์‚ฝ์ž…๋˜์ง€ ์•Š๊ณ  ๋งŒ์•ฝ 3๋ฒˆ ์ธ๋ฑ์Šค์— ์—˜๋ฆฌ๋จผํŠธ๊ฐ€ ์‚ฝ์ž…๋  ๊ฒฝ์šฐ์—” ๋’ค์ชฝ์— ์œ„์น˜ํ•œ ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ์ƒˆ๋กœ์šด ์—˜๋ฆฌ๋จผํŠธ๋กœ ์ธ์‹ํ•˜๊ณ  4๋ฒˆ ์ธ๋ฑ์Šค๋ถ€ํ„ฐ ๊ทธ ๋’ค์˜ ๋ชจ๋“  ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ๋ฆฌ๋ Œ๋”๋งํ•œ๋‹ค. ๋•Œ๋ฌธ์— React์—์„œ๋Š” ๋ฆฌ์ŠคํŒ… ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ Œ๋”ํ•  ๋•Œ key๊ฐ’์„ ์š”๊ตฌํ•œ๋‹ค. ์ด key๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์—˜๋ฆฌ๋จผํŠธ์˜ ์ธ๋ฑ์Šค๊ฐ€ ๋ณ€๊ฒฝ๋œ๋‹คํ•ด๋„ ๊ธฐ์กด๊ณผ ๋™์ผํ•˜๋‹ค๋Š” ๊ฒƒ์„ ํ™•์ธํ•˜๊ณ  ๊ทธ์ € ์œ„์น˜๋งŒ ์ด๋™ํ•œ๋‹ค.

const fruits = [{
  id: "1",
  name: "banana"
}, {
  id: "2",
  name: "apple"
}, {
  id: "3",
  name: "orange"
}];

function ArrayRenderComponents() {
  return (
    <ul>
      {fruits.map((fruit) => (
          <li key={fruit.id}>{fruit.name}</li>
      ))}
    </ul>
  );
}

<ul>
  <li key="1">banana</li>
  <li key="2">apple</li>
  <li key="3">orange</li>
</ul>

์—˜๋ฆฌ๋จผํŠธ๊ฐ€ ๋ฐฐ์—ด์— ์‚ฝ์ž…๋œ๋‹ค๋ฉด?


<ul>
  <li key="1">banana</li>
  <li key="2">apple</li>
  <li key="4">mango</li>
  <li key="3">orange</li>
</ul>

key prop์„ ํ†ตํ•ด React๊ฐ€ ๊ธฐ์กด๊ณผ ๋™์ผํ•œ ์—˜๋ฆฌ๋จผํŠธ์ž„์„ ํ™•์ธํ•˜๊ณ  ์œ„์น˜๋งŒ ์ด๋™!


4. ์„ ์–ธ์  API

๊ฐœ๋ฐœ์ž๊ฐ€ DOM element๋ฅผ ์„ ํƒํ•ด addEventLinster๋กœ ์ด๋ฒคํŠธ๋ฅผ ๋“ฑ๋กํ•˜๊ฑฐ๋‚˜, classList๋ฅผ add ํ•˜๊ฑฐ๋‚˜, ์–ด๋– ํ•œ ๋ถ€๋ชจ ๋…ธ๋“œ์˜ ์ž์‹ ์—˜๋ฆฌ๋จผํŠธ๋กœ ์ถ”๊ฐ€๋  ์ง€ ์ง์ ‘ DOM ์กฐ์ž‘๊ณผ ์ƒํƒœ ๋ณ€ํ™”์— ๋Œ€ํ•ด ๋ช…๋ นํ•  ํ•„์š”์—†์ด ์„ ์–ธ์ ์œผ๋กœ React์—๊ฒŒ UI๋ฅผ ์–ด๋–ป๊ฒŒ ํ‘œํ˜„ํ•ด์•ผ ํ•˜๋Š”์ง€๋ฅผ ์•Œ๋ ค์ฃผ๋Š” ๋ฐฉ์‹์ด๋‹ค.

์„ ์–ธ์  API์™€ Virtual DOM์ด ๋ฌด์Šจ ์ƒ๊ด€์ธ๊ฐ€?

์„ ์–ธ์ ์œผ๋กœ UI ๊ตฌ์กฐ๋ฅผ ์ž‘์„ฑํ•˜๊ณ , ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ฐ˜ํ™˜ํ•œ React element ํŠธ๋ฆฌ๊ฐ€ Virtual DOM์ด๋ฉฐ ์ƒํƒœ, ํƒ€์ž…์ด ๋ณ€๊ฒฝ๋์„ ๊ฒฝ์šฐ Real DOM๊ณผ ๋น„๊ต(diffing) ์ˆœํšŒํ•˜์—ฌ ๋ฆฌ๋ Œ๋”๋ง ์ตœ์ ํ™”๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š”๋ฐ ์ด ๊ณผ์ •์„ React์—๊ฒŒ ์„ ์–ธ์ ์œผ๋กœ ์•Œ๋ ค์ฃผ๋ฉด ์•Œ์•„์„œ ์ฒ˜๋ฆฌํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.


๊ถ๊ธˆํ•œ ํ‚ค์›Œ๋“œ

  • React Fiber

Last updated