Skip to content

Latest commit

ย 

History

History
391 lines (310 loc) ยท 15.6 KB

react-conponent-element-instance.md

File metadata and controls

391 lines (310 loc) ยท 15.6 KB

๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ, ์—˜๋ฆฌ๋จผํŠธ, ์ธ์Šคํ„ด์Šค

๋ฆฌ์•กํŠธ ๋ธ”๋กœ๊ทธ์— ์žˆ๋Š” "React Components, Elements, and Instances" ๊ธ€์„ ๋ฒˆ์—ญํ•˜๋ฉด์„œ ์ •๋ฆฌํ•œ ๊ธ€์ด๋‹ค(์•„์ฃผ ๋งŽ์ด ํ‹€๋ฆด ์ˆ˜ ์žˆ์Œ ์ฃผ์˜). ๋ฆฌ์•กํŠธ์˜ ์ปดํฌ๋„ŒํŠธ, ์—˜๋ฆฌ๋จผํŠธ, ์ธ์Šคํ„ด์Šค์˜ ์ฐจ์ด๋ฅผ ์•Œ์•„๋ณด์ž.

์ธ์Šคํ„ด์Šค ๊ด€๋ฆฌ

๋ฆฌ์•กํŠธ๋ฅผ ์ฒ˜์Œ ๋ฐฐ์šด๋‹ค๋ฉด, ์ปดํฌ๋„ŒํŠธ ํด๋ž˜์Šค์™€ ์ธ์Šคํ„ด์Šค๋งŒ ์‚ฌ์šฉํ•ด๋ดค์„ ๊ฒƒ์ด๋‹ค. ์˜ˆ๋ฅผ๋“ค์–ด, Button ์ปดํฌ๋„ŒํŠธ๋ฅผ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด์„œ ์„ ์–ธํ–ˆ์„ ๊ฒƒ์ด๋‹ค. ์•ฑ์ด ๋™์ž‘ํ•˜๊ณ  ์žˆ์„ ๋•Œ, ์ด ์ปดํฌ๋„ŒํŠธ์˜ ์—ฌ๋Ÿฌ ์ธ์Šคํ„ด์Šค๊ฐ€ ์Šคํฌ๋ฆฐ์— ์žˆ์„ ๊ฒƒ์ด๋ฉฐ, ๊ฐ๊ฐ์˜ ์ธ์Šคํ„ด์Šค๋Š” ๊ฐ์ž์˜ ํ”„๋กœํผํ‹ฐ์™€ ๋กœ์ปฌ ์ƒํƒœ๋ฅผ ๊ฐ–๊ณ  ์žˆ๋‹ค. ์ด๊ฒƒ์ด ์ „ํ†ต์ ์ธ object-oriented UI ํ”„๋กœ๊ทธ๋ž˜๋ฐ์ด๋‹ค.

์ด๋Ÿฌํ•œ ์ „ํ†ต์ ์ธ UI ๋ชจ๋ธ์—์„œ ์ž์‹ ์ปดํฌ๋„ŒํŠธ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์—†์• ๋Š” ๊ฒƒ์„ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์€ ์ „์ ์œผ๋กœ ๋‹น์‹ ์˜ ๋ชซ์ด๋‹ค. ๋งŒ์•ฝ Form ์ปดํฌ๋„ŒํŠธ๊ฐ€ Button ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ Œ๋”๋งํ•˜๊ณ ์ž ํ•  ๋•Œ, Form ์ปดํฌ๋„ŒํŠธ๋Š” ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ค๊ณ , ์ƒˆ๋กœ์šด ์ •๋ณด๋ฅผ ์ˆ˜๋™์œผ๋กœ ์—…๋ฐ์ดํŠธํ•ด์•ผ ํ•œ๋‹ค.

class Form extends TraditionalObjectOrientedView {
  render() {
    // Read some data passed to the view
    const { isSubmitted, buttonText } = this.attrs;

    if (!isSubmitted && !this.button) {
      // Form is not yet submitted. Create the button!
      this.button = new Button({
        children: buttonText,
        color: 'blue'
      });
      this.el.appendChild(this.button.el);
    }

    if (this.button) {
      // The button is visible. Update its text!
      this.button.attrs.children = buttonText;
      this.button.render();
    }

    if (isSubmitted && this.button) {
      // Form was submitted. Destroy the button!
      this.el.removeChild(this.button.el);
      this.button.destroy();
    }

    if (isSubmitted && !this.message) {
      // Form was submitted. Show the success message!
      this.message = new Message({ text: 'Success!' });
      this.el.appendChild(this.message.el);
    }
  }
}

๊ฐ ์ปดํฌ๋„ŒํŠธ ์ธ์Šคํ„ด์Šค๋Š” ๊ทธ DOM ๋…ธ๋“œ์™€ ์ž์‹ ์ปดํฌ๋„ŒํŠธ์˜ ์ธ์Šคํ„ด์Šค์— ๋Œ€ํ•œ ์ฐธ์กฐ๋ฅผ ๊ฐ–๊ณ  ์žˆ์–ด์•ผ ํ•œ๋‹ค. ๋˜ํ•œ, ์ ์ ˆํ•œ ๋•Œ์— ๊ทธ๊ฒƒ๋“ค์„ ์ƒ์„ฑํ•˜๊ณ , ์—…๋ฐ์ดํŠธํ•˜๊ณ , ์—†์• ์•ผ ํ•œ๋‹ค.

์ฝ”๋“œ์˜ ๋ผ์ธ ์ˆ˜๋Š” ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๊ฐ–๊ณ  ์žˆ๋Š” ์ƒํƒœ์˜ ์ˆ˜๊ฐ€ ๋Š˜์–ด๋‚จ์— ๋”ฐ๋ผ ๊ทธ๋ฆฌ๊ณ  ๋ถ€๋ชจ๊ฐ€ ์ž์‹ ์ปดํฌ๋„ŒํŠธ ์ธ์Šคํ„ด์Šค์— ์ง์ ‘ ์ ‘๊ทผํ•จ์— ๋”ฐ๋ผ ์ ์ฐจ ๋Š˜์–ด๋‚  ๊ฒƒ์ด๋‹ค. ๋ฏธ๋ž˜์— ๊ทธ๊ฒƒ๋“ค์„ ๋ถ„๋ฆฌํ•˜๋Š” ๊ฒƒ์„ ๋”์šฑ ์–ด๋ ต๊ฒŒ ๋งŒ๋“ ๋‹ค.

๋ฆฌ์•กํŠธ๋Š” ์–ด๋–ป๊ฒŒ ๋‹ค๋ฅผ๊นŒ?

์—˜๋ฆฌ๋จผํŠธ๊ฐ€ ํŠธ๋ฆฌ๋ฅผ ํ‘œํ˜„ํ•˜๋‹ค

๋ฆฌ์•กํŠธ์—์„œ๋Š” element๊ฐ€ ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๋“ฑ์žฅํ–ˆ๋‹ค.

An element is a plain object describing a component instance or DOM node and its desired properties

์—˜๋ฆฌ๋จผํŠธ๋Š” ์ปดํฌ๋„ŒํŠธ ์ธ์Šคํ„ด์Šค๋‚˜ DOM ๋…ธ๋“œ๋ฅผ ๊ธฐ์ˆ ํ•˜๋Š” ์ˆœ์ˆ˜ํ•œ ๊ฐ์ฒด์ด๋‹ค. ์—˜๋ฆฌ๋จผํŠธ๋Š” component type(์˜ˆ๋ฅผ ๋“ค๋ฉด, ๋ฒ„ํŠผ)๊ณผ ๊ทธ properties(์˜ˆ๋ฅผ ๋“ค๋ฉด, color), ๊ทธ๋ฆฌ๊ณ  ๊ทธ ๋‚ด๋ถ€์˜ child element์— ๋Œ€ํ•œ ์ •๋ณด๋งŒ ๊ฐ–๊ณ  ์žˆ๋‹ค.

์—˜๋ฆฌ๋จผํŠธ๋Š” ์‹ค์ œ ์ธ์Šคํ„ด์Šค๋Š” ์•„๋‹ˆ๋‹ค. ์—˜๋ฆฌ๋จผํŠธ๋Š” ์Šคํฌ๋ฆฐ์—์„œ ๋ณด๊ณ ์ž ํ•˜๋Š” ๊ฒƒ์„ ๋ฆฌ์•กํŠธ์—๊ฒŒ ์•Œ๋ ค์ฃผ๋Š” ๋ฐฉ์‹์ด๋‹ค. ์—˜๋ฆฌ๋จผํŠธ์— ์–ด๋– ํ•œ ๋ฉ”์†Œ๋“œ๋„ ํ˜ธ์ถœํ•  ์ˆ˜ ์—†๋‹ค. ์—˜๋ฆฌ๋จผํŠธ๋Š” ๊ทธ์ € ๋‘ ๊ฐ€์ง€ ํ•„๋“œ์— ๋Œ€ํ•œ immutable description object์ด๋‹ค. type:(string | ReactClass), props: Object

DOM Elements

์—˜๋ฆฌ๋จผํŠธ์˜ ํƒ€์ž…์ด string์ด๋ฉด, ๊ทธ๊ฒƒ์€ ํƒœ๊ทธ ์ด๋ฆ„์œผ๋กœ DOM node๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ๊ฒƒ์ด๊ณ , props๋Š” ๊ทธ ์†์„ฑ์— ํ•ด๋‹นํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

{
  type: 'button',
  props: {
    className: 'button button-blue',
    children: {
      type: 'b',
      props: {
        children: 'OK!'
      }
    }
  }
}

์œ„์˜ ์—˜๋ฆฌ๋จผํŠธ๋Š” ๋‹ค์Œ HTML์„ ์ˆœ์ˆ˜ ๊ฐ์ฒด๋กœ ํ‘œํ˜„ํ•œ ๋ฐฉ์‹์ด๋‹ค.

<button class='button button-blue'>
  <b>
    OK!
  </b>
</button>

๊ฐ ์—˜๋ฆฌ๋จผํŠธ๊ฐ€ ์–ด๋–ป๊ฒŒ ์ค‘์ฒฉ๋˜์–ด ์žˆ๋Š”์ง€๋ฅผ ์ฃผ๋ชฉํ•˜๋ผ. ์ปจ๋ฒค์…˜์— ์˜ํ•ด, ์—˜๋ฆฌ๋จผํŠธ ํŠธ๋ฆฌ๋ฅผ ๋งŒ๋“ค๊ณ  ์‹ถ์„ ๋•Œ, ํ•˜๋‚˜ ์ด์ƒ์˜ child elements๋ฅผ ๊ทธ๊ฒƒ์ด ์†ํ•œ ์—˜๋ฆฌ๋จผํŠธ์˜ children prop์œผ๋กœ ๋ช…์‹œํ•˜๊ฒŒ ๋œ๋‹ค.

์ค‘์š”ํ•œ ๊ฒƒ์€ child์™€ parent ์—˜๋ฆฌ๋จผํŠธ ๋ชจ๋‘, ๊ทธ์ € description์ผ ๋ฟ์ด์ง€ ์‹ค์ œ ์ธ์Šคํ„ด์Šค๊ฐ€ ์•„๋‹ˆ๋ผ๋Š” ๊ฒƒ์ด๋‹ค. ์—˜๋ฆฌ๋จผํŠธ๋“ค์„ ๋งŒ๋“ค ๋•Œ, ์Šคํฌ๋ฆฐ์—์„œ์˜ ์–ด๋– ํ•œ ๊ฒƒ๋„ ์ฐธ์กฐํ•˜์ง€ ์•Š๋Š”๋‹ค. ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ๋งŒ๋“ค๊ณ  ๋ฒ„๋ฆฌ๋Š” ๊ฒƒ์€ ํฌ๊ฒŒ ๋ฌธ์ œ๊ฐ€ ๋˜์ง€ ์•Š๋Š”๋‹ค.

๋ฆฌ์•กํŠธ ์—˜๋ฆฌ๋จผํŠธ๋Š” ์ˆœํšŒํ•˜๊ธฐ ์‰ฌ์šฐ๋ฉฐ, ํŒŒ์‹ฑํ•  ํ•„์š”๋„ ์—†๋‹ค. ์‹ค์ œ DOM elements๋ณด๋‹ค ํ›จ์”ฌ ๋” ๊ฐ€๋ณ๋‹ค. ๋ฆฌ์•กํŠธ ์—˜๋ฆฌ๋จผํŠธ๋Š” ๊ทธ์ € ๊ฐ์ฒด์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. (๊ฐ์ฒด๋‹ˆ๊นŒ ๋ฐ”๋กœ ์ ‘๊ทผํ•˜๋ฉด ๋˜๋ฏ€๋กœ, ์ˆœํšŒํ•˜๊ธฐ ์‰ฝ๊ณ  ํŒŒ์‹ฑํ•  ํ•„์š”๋„ ์—†๋‹ค๊ณ  ํ•˜๋Š” ๊ฒƒ ๊ฐ™๋‹ค)

Component Elements

์—˜๋ฆฌ๋จผํŠธ์˜ ํƒ€์ž…์ด ์ŠคํŠธ๋ง์ด ์•„๋‹ˆ๋ผ, ๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ์— ํ•ด๋‹นํ•˜๋Š” ํด๋ž˜์Šค๋‚˜ ํ•จ์ˆ˜์ผ ์ˆ˜๋„ ์žˆ๋‹ค.

{
  type: Button,
  props: {
    color: 'blue',
    children: 'OK!'
  }
}

๋‹ค์Œ์€ ๋ฆฌ์•กํŠธ์˜ ํ•ต์‹ฌ ์•„์ด๋””์–ด์ด๋‹ค.

An element describing a component is also an element, just like an element describing the DOM node. They can be nested and mixed with each other.

์ปดํฌ๋„ŒํŠธ๋ฅผ ํ‘œํ˜„ํ•˜๋Š” ์—˜๋ฆฌ๋จผํŠธ ๋˜ํ•œ ์—˜๋ฆฌ๋จผํŠธ์ด๋‹ค. DOM๋…ธ๋“œ๋ฅผ ํ‘œํ˜„ํ•˜๋Š” ์—˜๋ฆฌ๋จผํŠธ๊ฐ€ ์—˜๋ฆฌ๋จผํŠธ์ธ ๊ฒƒ๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€์ธ ๊ฒƒ์ด๋‹ค. ๊ทธ๊ฒƒ๋“ค์€ ์„œ๋กœ ์ค‘์ฒฉ๋  ์ˆ˜ ์žˆ์œผ๋ฉฐ ์„ž์ผ ์ˆ˜ ์žˆ๋‹ค.

์ด๋Ÿฌํ•œ ํŠน์„ฑ์€ ์ปฌ๋Ÿฌ ์†์„ฑ์„ ๊ฐ€์ง„ Button ํƒ€์ž…์˜DangerButton์„ ์ •์˜ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•œ๋‹ค. ์ด DangerButton์€ Button์ด๋ผ๋Š” ๊ฒƒ์ด <button>, <div> ํ˜น์€ ๋‹ค๋ฅธ ์–ด๋– ํ•œ ํƒœ๊ทธ๋กœ ๋ Œ๋”๋ง๋ ์ง€์— ๋Œ€ํ•œ ๊ฑฑ์ •์„ ์ „ํ˜€ํ•˜์ง€ ์•Š๊ฒŒ ๋œ๋‹ค.

const DangerButton = ({ children }) => ({
  type: Button,
  props: {
    color: 'red',
    children: children
  }
});

ํ•˜๋‚˜์˜ ์—˜๋ฆฌ๋จผํŠธ ํŠธ๋ฆฌ ์•ˆ์— DOM๊ณผ ์ปดํฌ๋„ŒํŠธ ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ๋ฏน์Šคํ•˜๊ฑฐ๋‚˜ ๋งค์น˜์‹œํ‚ฌ ์ˆ˜๋„ ์žˆ๋‹ค.

const DeleteAccount = () => ({
  type: 'div',
  props: {
    children: [{
      type: 'p',
      props: {
        children: 'Are you sure?'
      }
    }, {
      type: DangerButton,
      props: {
        children: 'Yep'
      }
    }, {
      type: Button,
      props: {
        color: 'blue',
        children: 'Cancel'
      }
   }]
});

JSX๋ผ๋ฉด ๋‹ค์Œ์ฒ˜๋Ÿผ ํ‘œํ˜„๋œ๋‹ค.

const DeleteAccount = () => (
  <div>
    <p>Are you sure?</p>
    <DangerButton>Yep</DangerButton>
    <Button color='blue'>Cancel</Button>
  </div>
);

์ด๋Ÿฌํ•œ ๋ฏน์Šค ์•ค ๋งค์น˜๋Š” ์ปดํฌ๋„ŒํŠธ๋ผ๋ฆฌ ์„œ๋กœ ๋ถ„๋ฆฌ๋˜๊ฒŒ ํ•˜๋Š”๋ฐ ๋„์›€์ด ๋œ๋‹ค. ์ด๋Š” ๊ฐ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์กฐํ•ฉ์„ ํ†ตํ•ด ๋‘ _is-a_์™€ _has-a_๊ด€๊ณ„๊ฐ€ ๋ฐฐํƒ€์ ์œผ๋กœ ํ‘œํ˜„๋  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

  • Button is a DOM <button> with specific properties. (is-a)
  • DangerButton is a Button with specific properties. (is-a)
  • DeleteAccount contains a Button and a DangerButton inside a <div>. (has-a)

Component Encapsulate Element Trees

๋ฆฌ์•กํŠธ๊ฐ€ ํ•จ์ˆ˜๋‚˜ ํด๋ž˜์Šค ํƒ€์ž…์˜ ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ๋ณด๊ฒŒ ๋œ๋‹ค๋ฉด, ํ•ด๋‹นํ•˜๋Š” props์— ๊ด€ํ•˜์—ฌ ๊ทธ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์–ด๋– ํ•œ ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ๋ Œ๋”๋งํ• ์ง€ ๋ฌผ์–ด๋ณธ๋‹ค.

๋‹ค์Œ๊ณผ ๊ฐ™์€ ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ๋ณธ๋‹ค๋ฉด,

{
  type: Button,
  props: {
    color: 'blue',
    children: 'OK!'
  }
}

๋ฆฌ์•กํŠธ๋Š” Button ์ปดํฌ๋„ŒํŠธ์—๊ฒŒ ๋ฌด์—‡์„ ๋ Œ๋”๋งํ•  ๊ฒƒ์ธ์ง€๋ฅผ ๋ฌผ์–ด๋ณธ๋‹ค. ๊ทธ Button ์ปดํฌ๋„ŒํŠธ๋Š” ๋‹ค์Œ์˜ ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

{
  type: 'button',
  props: {
    className: 'button button-blue',
    children: {
      type: 'b',
      props: {
        children: 'OK!'
      }
    }
  }
}

๋ฆฌ์•กํŠธ๋Š” ์ด ๊ณผ์ •์„ ํŽ˜์ด์ง€์˜ ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ์—๊ฒŒ ๊ทธ ์•„๋ž˜์— ์žˆ๋Š” DOM ํƒœ๊ทธ ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ์•Œ ๋•Œ๊นŒ์ง€ ๋ฐ˜๋ณตํ•œ๋‹ค.

์œ„์— ์žˆ๋˜ Form ์˜ˆ์‹œ๋Š” ๋ฆฌ์•กํŠธ๋กœ ๋‹ค์Œ์ฒ˜๋Ÿผ ํ‘œํ˜„๋  ์ˆ˜ ์žˆ๋‹ค.

const Form = ({ isSubmitted, buttonText }) => {
  if (isSubmitted) {
    // Form submitted! Return a message element.
    return {
      type: Message,
      props: {
        text: 'Success!'
      }
    };
  }

  // Form is still visible! Return a button element.
  return {
    type: Button,
    props: {
      children: buttonText,
      color: 'blue'
    }
  };
};

๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ์—๊ฒŒ, props๋Š” Input์ด๋ฉฐ, element tree๊ฐ€ output์ด ๋œ๋‹ค.

๋ฐ˜ํ™˜๋œ element tree๋Š” DOM node๋ฅผ ์„ค๋ช…ํ•˜๋Š” ์—˜๋ฆฌ๋จผํŠธ์™€ ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์„ค๋ช…ํ•˜๋Š” ์—˜๋ฆฌ๋จผํŠธ๊ฐ€ ํฌํ•จ๋  ์ˆ˜ ์žˆ๋‹ค. ์ด๋Š” ๊ทธ ๋‚ด๋ถ€์˜ DOM ๊ตฌ์กฐ์— ๊ธฐ๋Œ€์ง€ ์•Š๊ณ , ๋…๋ฆฝ์ ์ธ UI๋ฅผ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค€๋‹ค.

๋ฆฌ์•กํŠธ๊ฐ€ instance๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ์—…๋ฐ์ดํŠธํ•˜๊ณ , ์—†์•ค๋‹ค. ์šฐ๋ฆฌ๋Š” ๊ทธ ์ธ์Šคํ„ด์Šค๋ฅผ ์ปดํฌ๋„ŒํŠธ๋กœ๋ถ€ํ„ฐ ๋ฐ˜ํ™˜ํ•œ ์—˜๋ฆฌ๋จผํŠธ๋“ค๋กœ ํ‘œํ˜„ํ•˜๋ฉฐ, ๋ฆฌ์•กํŠธ๋Š” ๊ทธ ์ธ์Šคํ„ด์Šค๋ฅผ ๊ด€๋ฆฌํ•œ๋‹ค.

์ปดํฌ๋„ŒํŠธ๋Š” ํด๋ž˜์Šค์ด๊ฑฐ๋‚˜ ํ•จ์ˆ˜์ผ ์ˆ˜ ์žˆ๋‹ค

์œ„ ์ฝ”๋“œ์—์„œ Form, Message, Button์€ ๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ์ด๋‹ค. ์ด๊ฒƒ๋“ค์€ ํ•จ์ˆ˜๋กœ ์“ฐ์—ฌ์งˆ ์ˆ˜ ์žˆ๊ณ , React.Component๋กœ ๋ถ€ํ„ฐ ๋‚ด๋ ค์˜จ ํด๋ž˜์Šค๋กœ ์“ฐ์—ฌ์งˆ ์ˆ˜๋„ ์žˆ๋‹ค. ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ •์˜ํ•˜๋Š” ์„ธ ๊ฐ€์ง€ ๋ฐฉ์‹๋“ค์€ ๊ฑฐ์˜ ๋™์ผํ•˜๋‹ค.

// 1) As a function of props
const Button = ({ children, color }) => ({
  type: 'button',
  props: {
    className: 'button button-' + color,
    children: {
      type: 'b',
      props: {
        children: children
      }
    }
  }
});

// 2) Using the React.createClass() factory
const Button = React.createClass({
  render() {
    const { children, color } = this.props;
    return {
      type: 'button',
      props: {
        className: 'button button-' + color,
        children: {
          type: 'b',
          props: {
            children: children
          }
        }
      }
    };
  }
});

// 3) As an ES6 class descending from React.Component
class Button extends React.Component {
  render() {
    const { children, color } = this.props;
    return {
      type: 'button',
      props: {
        className: 'button button-' + color,
        children: {
          type: 'b',
          props: {
            children: children
          }
        }
      }
    };
  }
}

์ปดํฌ๋„ŒํŠธ๊ฐ€ ํด๋ž˜์Šค๋กœ ์ •์˜๋˜๋ฉด, ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ๋ณด๋‹ค ์กฐ๊ธˆ ๋” ํŒŒ์›Œํ’€ํ•˜๋‹ค. ํด๋ž˜์Šคํ˜• ์ปดํฌ๋„ŒํŠธ๋Š” ๋กœ์ปฌ ์ƒํƒœ๋ฅผ ์ €์žฅํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๊ทธ์— ํ•ด๋‹นํ•˜๋Š” DOM node๊ฐ€ ์ƒ์„ฑ๋˜๊ฑฐ๋‚˜ ์‚ญ์ œ๋˜์—ˆ์„ ๋•Œ, ์ปค์Šคํ…€ ๋กœ์ง์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ๋Š” ๋œ ํŒŒ์›Œํ’€ํ•˜์ง€๋งŒ, ๋” ๊ฐ„๋‹จํ•˜๋ฉฐ, render() ๋ฉ”์„œ๋“œ๋กœ ํด๋ž˜์Šคํ˜• ์ปดํฌ๋„ŒํŠธ์ฒ˜๋Ÿผ ํ–‰๋™ํ•  ์ˆ˜ ์žˆ๋‹ค.

ํด๋ž˜์Šคํ˜•์—๋งŒ ์žˆ๋Š” ํŠน์ง•์ด ํ•„์š”ํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด, ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•  ๊ฒƒ์„ ๊ถŒ์žฅํ•œ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜, ํ•จ์ˆ˜๋‚˜ ํด๋ž˜์Šค๋‚˜ ๊ทธ ๋ฐ”ํƒ•์— ์žˆ์–ด์„œ๋Š” ๋ฆฌ์•กํŠธ์—๊ฒŒ ์žˆ์–ด์„œ ๋ชจ๋‘ ์ปดํฌ๋„ŒํŠธ์ด๋‹ค. ๊ทธ ์ปดํฌ๋„ŒํŠธ๋“ค์€ props๋ฅผ ์ธํ’‹์œผ๋กœ ๋ฐ›์œผ๋ฉฐ, ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ์•„์›ƒํ’‹์œผ๋กœ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

Top-down Reconciliation (ํ•˜ํ–ฅ์‹ ์กฐํ™”)

๋‹ค์Œ์„ ํ˜ธ์ถœํ–ˆ๋‹ค๊ณ  ํ•˜์ž.

ReactDOM.render({
  type: Form,
  props: {
    isSubmitted: false,
    buttonText: 'OK!'
  }
}, document.getElementById('root'));

๋ฆฌ์•กํŠธ๋Š” Form ์ปดํฌ๋„ŒํŠธ์—๊ฒŒ ์ฃผ์–ด์ง„ props๋กœ ์–ด๋– ํ•œ ์—˜๋ฆฌ๋จผํŠธ ํŠธ๋ฆฌ๋ฅผ ๋ฐ˜ํ™˜ํ•  ๊ฒƒ์ธ์ง€๋ฅผ ๋ฌผ์–ด๋ณธ๋‹ค. ๋ฆฌ์•กํŠธ๋Š” ๋” ๊ฐ„๋‹จํ•œ primitive ์ธก๋ฉด์—์„œ ์ปดํฌ๋„ŒํŠธ ํŠธ๋ฆฌ์— ๋Œ€ํ•œ ์ดํ•ด๋ฅผ ์ ์ฐจ refiningํ•˜๊ฒŒ ๋œ๋‹ค.

// React: You told me this...
{
  type: Form,
  props: {
    isSubmitted: false,
    buttonText: 'OK!'
  }
}

// React: ...And Form told me this...
{
  type: Button,
  props: {
    children: 'OK!',
    color: 'blue'
  }
}

// React: ...and Button told me this! I guess I'm done.
{
  type: 'button',
  props: {
    className: 'button button-blue',
    children: {
      type: 'b',
      props: {
        children: 'OK!'
      }
    }
  }
}

์ด๊ฒƒ์€ ๋ฆฌ์•กํŠธ๊ฐ€ reconciliation์„ ํ˜ธ์ถœํ•˜๋Š” ๊ณผ์ •์˜ ์ผ๋ถ€์ด๋‹ค. Reconciliation์€ ReactDOM.render()๋‚˜ setState()๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ, ์‹œ์ž‘๋œ๋‹ค.

reconciliation์ด ๋๋‚  ๋•Œ, ๋ฆฌ์•กํŠธ๋Š” DOM tree์˜ ๊ฒฐ๊ณผ๋ฅผ ์•Œ๊ฒŒ ๋˜๋ฉฐ, react-dom์ด๋‚˜ react-native๊ฐ™์€ renderer๊ฐ€ ๋” ๋…ธ๋“œ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๊ธฐ ์œ„ํ•ด ํ•„์š”ํ•œ ์ž‘์€ ๋ณ€ํ™”์˜ ์ง‘ํ•ฉ์„ ์ ์šฉํ•œ๋‹ค.

์ด๋Ÿฌํ•œ ์ ์ง„์ ์ธ ์ •์ œ ์ž‘์—…์€ ๋ฆฌ์•กํŠธ์•ฑ์ด ์ตœ์ ํ™”ํ•˜๊ธฐ ์‰ฝ๋‹ค๋Š” ๊ฒƒ์˜ ์ด์œ ๊ฐ€ ๋œ๋‹ค.

์ปดํฌ๋„ŒํŠธ ํŠธ๋ฆฌ์˜ ์–ด๋– ํ•œ ๋ถ€๋ถ„์ด ๋„ˆ๋ฌด ์ปค์ ธ์„œ ๋ฆฌ์•กํŠธ๊ฐ€ ํšจ๊ณผ์ ์œผ๋กœ ๋ฐฉ๋ฌธํ•  ์ˆ˜ ์—†์„ ๋•Œ, "refining"ํ•˜๋Š” ์ž‘์—…์„ ์Šคํ‚ตํ•˜๊ณ , ํŠธ๋ฆฌ์˜ ํŠน์ • ํŒŒํŠธ์— ๋‹ค๋ฅธ ์ ์ด ์žˆ๋Š”์ง€๋ฅผ ์ฐพ์œผ๋ฉฐ ๊ทธ props์— ๋ณ€ํ™”๊ฐ€ ์—†๋Š”์ง€๋ฅผ ํŒŒ์•…ํ•˜๊ฒŒ ํ•œ๋‹ค.

props๊ฐ€ immutableํ•˜๋‹ค๋ฉด, ๊ทธ props๊ฐ€ ๋ณ€ํ™”ํ–ˆ๋Š”์ง€ ํŒŒ์•…ํ•˜๋Š” ๊ฒƒ์„ ๊ณ„์‚ฐํ•˜๋Š” ๊ฒƒ์€ ๋งค์šฐ ๋น ๋ฅด๋‹ค. ๋”ฐ๋ผ์„œ ๋ฆฌ์•กํŠธ์™€ immutability ์ž‘์—…์€ ํ•จ๊ป˜ ํ•  ๋•Œ ๋งค์šฐ ์ข‹๊ณ , ์ ์€ ๋…ธ๋ ฅ์œผ๋กœ๋„ ํฐ ์ตœ์ ํ™”๊ฐ€ ์ด๋ฃจ์–ด์ง„๋‹ค.

์ด ๋ธ”๋กœ๊ทธ๋Š” ์ปดํฌ๋„ŒํŠธ์™€ ์—˜๋ฆฌ๋จผํŠธ์— ๋Œ€ํ•ด์„œ๋งŒ ๋งŽ์ด ๋งํ•˜๊ณ , ์ธ์Šคํ„ด์Šค์— ๋Œ€ํ•ด์„œ๋Š” ๊ทธ๋‹ค์ง€ ๋งŽ์ด ๋งํ•˜์ง€ ์•Š์€ ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์—ˆ์„ ๊ฒƒ์ด๋‹ค. ์ธ์Šคํ„ด์Šค๋Š” ์‚ฌ์‹ค ๋Œ€๋ถ€๋ถ„์˜ ๊ฐ์ฒด ์ง€ํ–ฅ์ ์ธ UI ํ”„๋ ˆ์ž„์›Œํฌ๋ณด๋‹ค ๋ฆฌ์•กํŠธ์—์„œ ํ›จ์”ฌ ์ค‘์š”ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

ํด๋ž˜์Šค๋กœ ์„ ์–ธ๋œ ์ปดํฌ๋„ŒํŠธ๋งŒ์ด ์ธ์Šคํ„ด์Šค๋ฅผ ๊ฐ–๊ณ  ์žˆ์œผ๋ฉฐ, ์ ˆ๋Œ€๋กœ ์ธ์Šคํ„ด์Šค๋ฅผ ์ง์ ‘ ๋งŒ๋“ค ์ˆ˜ ์—†๋‹ค. ์ด๋Š” ๋ฆฌ์•กํŠธ๊ฐ€ ์‚ฌ์šฉ์ž๋ฅผ ์œ„ํ•ด ๊ทธ๋ ‡๊ฒŒ ํ•œ ๊ฒƒ์ด๋‹ค. ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ ์ธ์Šคํ„ด์Šค๊ฐ€ ์ž์‹ ์ปดํฌ๋„ŒํŠธ ์ธ์Šคํ„ด์Šค์— ์ ‘๊ทผํ•˜๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜์€ ์กด์žฌํ•˜์ง€๋งŒ, ๊ทธ๊ฒƒ์€ ์˜ค์ง ํ”ผํ•  ์ˆ˜ ์—†๋Š” ํ–‰๋™(์˜ˆ๋ฅผ ๋“ค๋ฉด, field์— ํฌ์ปค์Šค๋ฅผ ์„ธํŒ…ํ•˜๋Š” ๊ฒƒ)์—์„œ๋งŒ ์‚ฌ์šฉ๋˜๋ฉฐ, ์ผ๋ฐ˜์ ์œผ๋กœ๋Š” ๋ฐ˜๋“œ์‹œ ํ”ผํ•ด์•ผ ํ•œ๋‹ค.

๋ฆฌ์•กํŠธ๋Š” ๋ชจ๋“  ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ์„ ๊ด€๋ฆฌํ•˜๋ฏ€๋กœ, ๋ฉ”์†Œ๋“œ์™€ ๋กœ์ปฌ State๋ฅผ ๊ฐ–๋Š” ๊ฐ์ฒด ์ง€ํ–ฅ์ ์ธ ๋ฐฉ์‹์œผ๋กœ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ธ์Šคํ„ด์Šค๋Š” ๋ฆฌ์•กํŠธ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ชจ๋ธ์—์„œ ๊ทธ๋‹ค์ง€ ์ค‘์š”ํ•˜์ง€ ์•Š์œผ๋ฉฐ, ์ธ์Šคํ„ด์Šค๋Š” ๋ฆฌ์•กํŠธ ๊ทธ ์ž์ฒด์— ์˜ํ•ด์„œ ๊ด€๋ฆฌ๋œ๋‹ค.

์š”์•ฝ

  • Element
    • ์—˜๋ฆฌ๋จผํŠธ๋Š” DOM node๋‚˜ ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ์— ๋Œ€ํ•ด ์Šคํฌ๋ฆฐ์— ๋ณด์—ฌ์กŒ์œผ๋ฉด ํ•˜๋Š” ๊ฒƒ์„ ๋‚˜ํƒ€๋‚ด๋Š” ์ˆœ์ˆ˜ ๊ฐ์ฒด์ด๋‹ค.
    • ์—˜๋ฆฌ๋จผํŠธ๋Š” ๋‹ค๋ฅธ ์—˜๋ฆฌ๋จผํŠธ๋ฅผ props๋กœ ๊ฐ–๊ณ  ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค.
    • React element๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ์€ ๋งค์šฐ ๊ฐ€๋ฒผ์šด ์ž‘์—…์ด๋‹ค(cheap).
    • ์—˜๋ฆฌ๋จผํŠธ๊ฐ€ ์ƒ์„ฑ๋˜๋ฉด, ์ ˆ๋Œ€๋กœ ๋ณ€ํ™”๋˜์ง€ ์•Š๋Š”๋‹ค.
    • ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” React.createElement()๋‚˜ JSX๋‚˜ element factory helper๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค. ์‹ค์ œ ์ฝ”๋“œ์—์„œ ์—˜๋ฆฌ๋จผํŠธ๋ฅผ plain object๋กœ ์“ฐ๋ฉด ์•ˆ๋œ๋‹ค. ๊ทธ์ € ์‹ค์ œ๋กœ๋Š” ์—˜๋ฆฌ๋จผํŠธ๊ฐ€ plain object๋ผ๋Š” ๊ฒƒ๋งŒ ์•Œ์•„๋‘์ž.
  • Component
    • ์ปดํฌ๋„ŒํŠธ๋Š” render()๋ฉ”์„œ๋“œ๊ฐ€ ์žˆ๋Š” ํด๋ž˜์Šค๋‚˜ ํ•จ์ˆ˜๋กœ ์ •์˜๋  ์ˆ˜ ์žˆ๋‹ค.
    • ๋‘ ๋ฐฉ์‹ ๋ชจ๋‘ props๋ฅผ ์ธํ’‹์œผ๋กœ ๋ฐ›์œผ๋ฉฐ, element tree๋ฅผ output์œผ๋กœ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
    • ์–ด๋– ํ•œ ์ปดํฌ๋„ŒํŠธ๊ฐ€ props๋ฅผ ์ธํ’‹์œผ๋กœ ๋ฐ›์„ ๋•Œ๋Š”, ํŠน์ • ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ํƒ€์ž…๊ณผ ๊ทธ props๊ฐ€ ์žˆ๋Š” element๋ฅผ ๋ฐ˜ํ™˜ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ด๋ฅผ ํ†ตํ•ด props๋Š” ๋ถ€๋ชจ์—์„œ ์ž์‹์œผ๋กœ ์ „๋‹ฌ๋œ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.
  • Instance
    • ์ธ์Šคํ„ด์Šค๋Š” ํด๋ž˜์Šคํ˜• ์ปดํฌ๋„ŒํŠธ์—์„œ this๋กœ ์ฐธ์กฐํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ์ด๋Š” ๋กœ์ปฌ ์ƒํƒœ์™€ ๋ผ์ดํ”„์‚ฌ์ดํด ์ด๋ฒคํŠธ์— ๋Œ€์‘ํ•˜๋Š” ๊ฒƒ์— ์œ ์šฉํ•˜๋‹ค.
    • ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ๋Š” ์ธ์Šคํ„ด์Šค๋ฅผ ์ „ํ˜€ ๊ฐ–๊ณ  ์žˆ์ง€ ์•Š๋‹ค. ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ๋งŒ์ด ์ธ์Šคํ„ด์Šค๋ฅผ ๊ฐ–๊ณ  ์žˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜, ๋ฆฌ์•กํŠธ๊ฐ€ ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ์„ ๊ด€๋ฆฌํ•˜๋ฏ€๋กœ, ์ง์ ‘ ์ปดํฌ๋„ŒํŠธ ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ค์ง€ ์•Š์•„๋„ ๋œ๋‹ค.

์ถœ์ฒ˜