We want to hear from you!Take our 2021 Community Survey!
This site is no longer updated.Go to react.dev

๊ตฌํ˜„ ์ฐธ๊ณ ์‚ฌํ•ญ

์ด ๋ถ€๋ถ„์€ ์Šคํƒ ์žฌ์กฐ์ •์ž(reconciler)์— ๋Œ€ํ•œ ๊ตฌํ˜„ ์ฐธ๊ณ ์‚ฌํ•ญ์ž…๋‹ˆ๋‹ค.

์ด๋Š” ๋งค์šฐ ๊ธฐ์ˆ ์ ์ด๊ณ  ๊ณต๊ฐœ๋œ React API๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์–ด๋–ป๊ฒŒ ์ฝ”์–ด, ๋ Œ๋”๋Ÿฌ, ์žฌ์กฐ์ •์ž๋กœ ๋‚˜๋ˆ„์–ด์ง€๋Š”์ง€์— ๋Œ€ํ•ด ๊นŠ์€ ์ดํ•ด๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์•„์ง React ์ฝ”๋“œ ๋ฒ ์ด์Šค์— ์นœ์ˆ™ํ•˜์ง€ ์•Š๋‹ค๋ฉด, ๋จผ์ € the codebase overview๋ฅผ ์ฝ๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค.

์ด๋Š” React ์ปดํฌ๋„ŒํŠธ์™€ ์ธ์Šคํ„ด์Šค ๊ทธ๋ฆฌ๊ณ  ์—˜๋ฆฌ๋จผํŠธ ์‚ฌ์ด์˜ ์ฐจ์ด์ ์„ ์ดํ•ดํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค.

์Šคํƒ ์žฌ์กฐ์ •์ž๋Š” React 15์™€ ๊ทธ ์ด์ „ ๋ฒ„์ „์— ์‚ฌ์šฉ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š”src/renderers/shared/stack/reconciler์— ์œ„์น˜ํ•ด ์žˆ์Šต๋‹ˆ๋‹ค.

๋น„๋””์˜ค: React ์ฒ˜์Œ๋ถ€ํ„ฐ ๋งŒ๋“ค๊ธฐ

Paul Oโ€™Shannessy๋Š” ์ด ๋ฌธ์„œ์— ํฌ๊ฒŒ ์˜๊ฐ์„ ์ฃผ์—ˆ๋˜ building React from scratch์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐ ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

์ด ๋ฌธ์„œ์™€ ๊ทธ์˜ ๋ง์€ ๋ชจ๋‘ ํ˜„์‹ค ์ฝ”๋“œ๋ฒ ์ด์Šค์˜ ๋‹จ์ˆœํ™”ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ์—ฌ๋Ÿฌ๋ถ„์€ ๋‘ ๊ฐ€์ง€ ๋ชจ๋‘ ์นœ์ˆ™ํ•ด ์ง์œผ๋กœ์จ ๋” ๊นŠ์€ ์ดํ•ด๋ฅผ ๊ฐ€์งˆ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ฐœ์š”

์žฌ์กฐ์ •์ž๋Š” ๊ณต๊ฐœ๋œ API๋ฅผ ๊ฐ€์ง€์ง€ ์•Š์Šต๋‹ˆ๋‹ค. React DOM๊ณผ React Native์™€ ๊ฐ™์€ ๋ Œ๋”๋Ÿฌ๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์“ด, React ์ปดํฌ๋„ŒํŠธ์— ๋”ฐ๋ฅธ ์‚ฌ์šฉ์ž ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ํšจ์œจ์ ์œผ๋กœ ์—…๋ฐ์ดํŠธ๋ฅผ ํ•˜๊ธฐ ์œ„ํ•ด์„œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

์žฌ๊ท€์ ์ธ ๊ณผ์ •์œผ๋กœ์จ์˜ ๋งˆ์šดํŠธ

์—ฌ๋Ÿฌ๋ถ„๋“ค์ด ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ฒ˜์Œ ๋งˆ์šดํŠธํ•  ๋•Œ๋ฅผ ๊ณ ๋ คํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

const root = ReactDOM.createRoot(rootEl);
root.render(<App />);

root.render๋Š” ์žฌ์กฐ์ •์ž๋ฅผ ํ†ตํ•ด <App />๋ฅผ ํ†ต๊ณผํ•˜๊ฒŒ ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. <App />์€ React ์—˜๋ฆฌ๋จผํŠธ์ด๋ฉฐ, ๋ Œ๋”๋ง ํ•  ๊ฒƒ์„ ์„ค๋ช…ํ•ด ๋†“์€ ๊ฒƒ์ž„์„ ๊ธฐ์–ตํ•ฉ์‹œ๋‹ค. ์ด๊ฒƒ์„ ํ‰๋ฒ”ํ•œ ๊ฐ์ฒด๋กœ ์ƒ๊ฐํ•ด๋„ ์ข‹์Šต๋‹ˆ๋‹ค.

console.log(<App />);
// { type: App, props: {} }

์žฌ์กฐ์ •์ž๊ฐ€ App์ด class์ธ์ง€ ํ•จ์ˆ˜์ธ์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

App์ด ํ•จ์ˆ˜๋ผ๋ฉด, ์žฌ์กฐ์ •์ž๋Š” ๋ Œ๋”๋ง ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•ด App(props)๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.

App์ด class๋ฉด, ์žฌ์กฐ์ •์ž๋Š” App์„ new App(props)๋กœ ์ธ์Šคํ„ด์Šคํ™” ํ•˜๊ณ , componentWillMount() ์ƒ๋ช…์ฃผ๊ธฐ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ ํ›„, render() ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๋ Œ๋”๋ง ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ๊ฐ€์ ธ์˜ค๊ฒŒ ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์–ด๋А ๊ฒฝ์šฐ๋“ , ์žฌ์กฐ์ •์ž๋Š” App์ด ๋ Œ๋”๋ง ๋˜๋Š” ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ํ•™์Šตํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ๊ณผ์ •์€ ์žฌ๊ท€์ ์ž…๋‹ˆ๋‹ค. App์€ <Greeting />์œผ๋กœ ๋ Œ๋”๋ง ๋  ์ˆ˜๋„ ์žˆ๊ณ , Greeting์€ <Button /> ๋˜๋Š” ๋‹ค๋ฅธ ๊ณณ์œผ๋กœ ๋ Œ๋”๋ง ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์žฌ์กฐ์ •์ž๋Š” ๊ฐ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ฌด์—‡์„ ๋ Œ๋”๋งํ•˜๋Š”์ง€ ํ•™์Šตํ•  ๋•Œ ์‚ฌ์šฉ์ž๊ฐ€ ์ •์˜ํ•œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์žฌ๊ท€์ ์œผ๋กœ ์กฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

์—ฌ๋Ÿฌ๋ถ„๋“ค์€ ์˜์‚ฌ์ฝ”๋“œ๋กœ ์ž‘์„ฑ๋œ ์ด ๊ณผ์ •์„ ์ƒ๊ฐํ•ด๋ด…์‹œ๋‹ค.

function isClass(type) {
  // React.Component subclasses have this flag
  return (
    Boolean(type.prototype) &&
    Boolean(type.prototype.isReactComponent)
  );
}

// This function takes a React element (e.g. <App />)
// and returns a DOM or Native node representing the mounted tree.
function mount(element) {
  var type = element.type;
  var props = element.props;

  // We will determine the rendered element
  // by either running the type as function
  // or creating an instance and calling render().
  var renderedElement;
  if (isClass(type)) {
    // Component class
    var publicInstance = new type(props);
    // Set the props
    publicInstance.props = props;
    // Call the lifecycle if necessary
    if (publicInstance.componentWillMount) {
      publicInstance.componentWillMount();
    }
    // Get the rendered element by calling render()
    renderedElement = publicInstance.render();
  } else {
    // Component function
    renderedElement = type(props);
  }

  // This process is recursive because a component may
  // return an element with a type of another component.
  return mount(renderedElement);

  // Note: this implementation is incomplete and recurses infinitely!
  // It only handles elements like <App /> or <Button />.
  // It doesn't handle elements like <div /> or <p /> yet.
}

var rootEl = document.getElementById('root');
var node = mount(<App />);
rootEl.appendChild(node);

์ฃผ์˜

์ด๋Š” ์˜์‚ฌ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค. ์‹ค์ œ ๊ตฌํ˜„๊ณผ ๋น„์Šทํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ์ด ๊ณผ์ •์„ ์–ธ์ œ ๋ฉˆ์ถœ ์ง€ ๊ฒฐ์ •์„ ํ•œ ์ ์ด ์—†๊ธฐ ๋•Œ๋ฌธ์— ์Šคํƒ ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ ๋˜ํ•œ ์•ผ๊ธฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์œ„์˜ ์˜ˆ์—์„œ ๋ช‡๊ฐ€์ง€ ํ•ต์‹ฌ ์•„์ด๋””์–ด๋ฅผ ์š”์•ฝํ•ด ๋ด…์‹œ๋‹ค.

  • React ์—˜๋ฆฌ๋จผํŠธ๋Š” ์ปดํฌ๋„ŒํŠธ ํƒ€์ž…(์˜ˆ: App)๊ณผ props๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ์ผ๋ฐ˜ ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค.
  • ์‚ฌ์šฉ์ž ์ •์˜๋œ ์ปดํฌ๋„ŒํŠธ(์˜ˆ: App)์€ class์ด๊ฑฐ๋‚˜ ํ•จ์ˆ˜์ผ ์ˆ˜ ์žˆ์ง€๋งŒ ๋ชจ๋‘ ์—˜๋ฆฌ๋จผํŠธ๋กœ ๋ Œ๋”๋ง๋ฉ๋‹ˆ๋‹ค.
  • โ€œ๋งˆ์šดํŒ…โ€์€ ์ตœ์ƒ์œ„ React ์—˜๋ฆฌ๋จผํŠธ(์˜ˆ: <App />)๋กœ๋ถ€ํ„ฐ DOM ๋˜๋Š” ๋„ค์ดํ‹ฐ๋ธŒ ํŠธ๋ฆฌ๋ฅผ ๋งŒ๋“œ๋Š” ์žฌ๊ท€์ ์ธ ๊ณผ์ •์ž…๋‹ˆ๋‹ค.

ํ˜ธ์ŠคํŠธ ์—˜๋ฆฌ๋จผํŠธ ๋งˆ์šดํŒ…

์ด ๊ณผ์ •์€ ์šฐ๋ฆฌ๊ฐ€ ์Šคํฌ๋ฆฐ์— ๋ฌด์–ธ๊ฐ€๋ฅผ ๋ Œ๋”๋งํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ๋ฌด์˜๋ฏธํ•ด์ง‘๋‹ˆ๋‹ค.

์‚ฌ์šฉ์ž ์ •์˜๋œ(โ€œcompositeโ€) ์ปดํฌ๋„ŒํŠธ ์™ธ์—๋„, React ์—˜๋ฆฌ๋จผํŠธ๋Š” ํ”Œ๋žซํผ ํŠน์œ ์˜(โ€œhostโ€) ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋‚˜ํƒ€๋‚ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, Button์€ ๋ Œ๋”๋ง๋œ ๋ฉ”์„œ๋“œ์—์„œ <div />๋ฅผ ๋ฆฌํ„ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์—˜๋ฆฌ๋จผํŠธ์˜ type์ด ๋ฌธ์ž์—ด์ธ ๊ฒฝ์šฐ, ์šฐ๋ฆฌ๋Š” ํ˜ธ์ŠคํŠธ ์—˜๋ฆฌ๋จผํŠธ๋กœ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

console.log(<div />);
// { type: 'div', props: {} }

์ด ๊ณณ์—๋Š” ํ˜ธ์ŠคํŠธ ์—˜๋ฆฌ๋จผํŠธ์™€ ๊ด€๋ จ๋œ ์‚ฌ์šฉ์ž ์ •์˜๋œ ์ฝ”๋“œ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

์žฌ์กฐ์ •์ž๊ฐ€ ํ˜ธ์ŠคํŠธ ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ๋งŒ๋‚˜๊ฒŒ ๋˜๋ฉด, ๋ Œ๋”๋Ÿฌ๊ฐ€ ํ˜ธ์ŠคํŠธ ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ๋งˆ์šดํŠธํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, React DOM์€ DOM ๋…ธ๋“œ๋ฅผ ์ƒ์„ฑํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

ํ˜ธ์ŠคํŠธ ์—˜๋ฆฌ๋จผํŠธ๊ฐ€ ์ž์‹์„ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉด, reconciler๊ฐ€ ์œ„์™€ ๋™์ผํ•œ ์•Œ๊ณ ๋ฆฌ์ฆ˜์— ๋”ฐ๋ผ ์žฌ๊ท€์ ์œผ๋กœ ์ž์‹์„ ๋งˆ์šดํŠธํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์ž์‹์ด ํ˜ธ์ŠคํŠธ(like <div><hr /></div>)์ธ์ง€ ์‚ฌ์šฉ์ž ์ •์˜(like <div><Button /></div>) ๋˜์—ˆ๋Š”์ง€๋Š” ์ƒ๊ด€์ด ์—†์Šต๋‹ˆ๋‹ค.

์ž์‹์— ์˜ํ•ด ๋งŒ๋“ค์–ด์ง„ DOM ๋…ธ๋“œ๋Š” ๋ถ€๋ชจ DOM ๋…ธ๋“œ๋กœ ์ถ”๊ฐ€๋˜๋ฉฐ, ์žฌ๊ท€์ ์œผ๋กœ ์ „์ฒด DOM ๊ตฌ์กฐ๊ฐ€ ์กฐ๋ฆฝ๋ฉ๋‹ˆ๋‹ค.

์ฃผ์˜

์žฌ์กฐ์ •์ž ์ž์ฒด๋Š” DOM์— ์—ฐ๊ฒฐ๋˜์–ด ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋งˆ์šดํŠธ์˜ ์ •ํ™•ํ•œ ๊ฒฐ๊ณผ(์†Œ์Šค ์ฝ”๋“œ์—์„œ โ€œmount imageโ€๋กœ ๋ถˆ๋ฆฌ๋Š”)๋Š” ๋ Œ๋”๋Ÿฌ์— ์˜์กดํ•˜๊ณ , DOM ๋…ธ๋“œ(React DOM), ๋ฌธ์ž์—ด(React DOM Server) ๋˜๋Š” ๋„ค์ดํ‹ฐ๋ธŒ ๋ทฐ์–ด(React Native)๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ์ˆซ์ž๊ฐ€ ๋  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ˜ธ์ŠคํŠธ ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ๋‹ค๋ฃจ๊ธฐ ์œ„ํ•ด ์ฝ”๋“œ๋ฅผ ํ™•์žฅํ•˜๋Š” ๊ฒฝ์šฐ, ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ณด์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

function isClass(type) {
  // React.Component subclasses have this flag
  return (
    Boolean(type.prototype) &&
    Boolean(type.prototype.isReactComponent)
  );
}

// This function only handles elements with a composite type.
// For example, it handles <App /> and <Button />, but not a <div />.
function mountComposite(element) {
  var type = element.type;
  var props = element.props;

  var renderedElement;
  if (isClass(type)) {
    // Component class
    var publicInstance = new type(props);
    // Set the props
    publicInstance.props = props;
    // Call the lifecycle if necessary
    if (publicInstance.componentWillMount) {
      publicInstance.componentWillMount();
    }
    renderedElement = publicInstance.render();
  } else if (typeof type === 'function') {
    // Component function
    renderedElement = type(props);
  }

  // This is recursive but we'll eventually reach the bottom of recursion when
  // the element is host (e.g. <div />) rather than composite (e.g. <App />):
  return mount(renderedElement);
}

// This function only handles elements with a host type.
// For example, it handles <div /> and <p /> but not an <App />.
function mountHost(element) {
  var type = element.type;
  var props = element.props;
  var children = props.children || [];
  if (!Array.isArray(children)) {
    children = [children];
  }
  children = children.filter(Boolean);

  // This block of code shouldn't be in the reconciler.
  // Different renderers might initialize nodes differently.
  // For example, React Native would create iOS or Android views.
  var node = document.createElement(type);
  Object.keys(props).forEach(propName => {
    if (propName !== 'children') {
      node.setAttribute(propName, props[propName]);
    }
  });

  // Mount the children
  children.forEach(childElement => {
    // Children may be host (e.g. <div />) or composite (e.g. <Button />).
    // We will also mount them recursively:
    var childNode = mount(childElement);

    // This line of code is also renderer-specific.
    // It would be different depending on the renderer:
    node.appendChild(childNode);
  });

  // Return the DOM node as mount result.
  // This is where the recursion ends.
  return node;
}

function mount(element) {
  var type = element.type;
  if (typeof type === 'function') {
    // User-defined components
    return mountComposite(element);
  } else if (typeof type === 'string') {
    // Platform-specific components
    return mountHost(element);
  }
}

var rootEl = document.getElementById('root');
var node = mount(<App />);
rootEl.appendChild(node);

์ด๋Š” ๋™์ž‘ํ•˜์ง€๋งŒ ์‹ค์ œ๋กœ ์žฌ์กฐ์ •์ž๊ฐ€ ๊ตฌํ˜„๋˜๋Š” ๋ฐฉ์‹๊ณผ๋Š” ๊ฑฐ๋ฆฌ๊ฐ€ ๋ฉ‰๋‹ˆ๋‹ค. ๋ˆ„๋ฝ๋œ ํ•ต์‹ฌ ์š”์†Œ๋Š” ์—…๋ฐ์ดํŠธ์— ๋Œ€ํ•œ ์ง€์›์ž…๋‹ˆ๋‹ค.

๋‚ด๋ถ€ ์ธ์Šคํ„ด์Šค์˜ ์†Œ๊ฐœ

React์˜ ๊ฐ€์žฅ ํฐ ํŠน์ง•์€ ๋ชจ๋“  ๊ฒƒ์„ ๋‹ค์‹œ ๋ Œ๋”๋งํ•  ์ˆ˜ ์žˆ๊ณ , DOM์„ ๋‹ค์‹œ ์ƒ์„ฑํ•˜๊ฑฐ๋‚˜ ์ƒํƒœ๋ฅผ ์ดˆ๊ธฐํ™”์‹œํ‚ค์ง€ ์•Š์•„๋„ ๋œ๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค.

root.render(<App />);
// Should reuse the existing DOM:
root.render(<App />);

๊ทธ๋Ÿฌ๋‚˜, ์œ„์˜ ๊ตฌํ˜„์€ ์ดˆ๊ธฐ ํŠธ๋ฆฌ๋ฅผ ์–ด๋–ป๊ฒŒ ๋งˆ์šดํŠธ ํ•˜๋Š”์ง€๋งŒ ์•Œ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋ชจ๋“  publicInstance์™€ ์–ด๋–ค DOM node๊ฐ€ ๊ฐ ์ปดํฌ๋„ŒํŠธ์— ๋Œ€์‘๋˜๋Š”์ง€์™€ ๊ฐ™์€ ํ•„์ˆ˜ ์ •๋ณด๋ฅผ ๋‹ด๊ณ  ์žˆ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์—…๋ฐ์ดํŠธ๋ฅผ ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

์Šคํƒ ์žฌ์กฐ์ •์ž์˜ ์ฝ”๋“œ๋ฒ ์ด์Šค๊ฐ€ mount() ํ•จ์ˆ˜๋ฅผ ๋ฉ”์„œ๋“œ๋กœ ๋งŒ๋“ค๊ณ  class์— ๋ฐฐ์น˜ํ•˜์—ฌ ์œ„์™€ ๊ฐ™์€ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์ ‘๊ทผ์—๋Š” ์—ฌ๋Ÿฌ ๋‹จ์ ์ด ์žˆ๊ณ , ํ˜„์žฌ ์šฐ๋ฆฌ๋Š” ์žฌ์กฐ์ •์ž๋ฅผ ๋‹ค์‹œ ์ž‘์„ฑํ•˜๊ณ  ์žˆ์œผ๋ฉฐ ์Šคํƒ ์žฌ์กฐ์ •์ž์™€๋Š” ๋‹ค๋ฅธ ๋ฐ˜๋Œ€ ๋ฐฉํ–ฅ์œผ๋กœ ๋‚˜์•„๊ฐ€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€๋งŒ, ์Šคํƒ ์žฌ์กฐ์ •์ž๊ฐ€ ์ง€๊ธˆ ์ž‘๋™ํ•˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.

mountHost์™€ mountComposite ํ•จ์ˆ˜๋ฅผ ๋ถ„๋ฆฌํ•˜๋Š” ๊ฒƒ ๋Œ€์‹ ์—, ์šฐ๋ฆฌ๋Š” DOMComponent์™€ CompositeComponent ์˜ ๋‘ ๊ฐ€์ง€ class๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

๋‘ class ๋ชจ๋‘ element๋ฅผ ๋ฐ›์•„๋“ค์ด๋Š” ์ƒ์„ฑ์ž ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๋งˆ์šดํŠธ๋œ ๋…ธ๋“œ๋ฅผ ๋ฐ˜ํ™˜ํ•ด์ฃผ๋Š” mount() ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ตœ์ƒ์œ„ mount() ํ•จ์ˆ˜๋ฅผ ์˜ฌ๋ฐ”๋ฅธ class๋กœ ์ธ์Šคํ„ด์Šคํ™” ํ•˜๋Š” ํŒฉํ† ๋ฆฌ๋กœ ๋Œ€์ฒดํ•ฉ๋‹ˆ๋‹ค.

function instantiateComponent(element) {
  var type = element.type;
  if (typeof type === 'function') {
    // User-defined components
    return new CompositeComponent(element);
  } else if (typeof type === 'string') {
    // Platform-specific components
    return new DOMComponent(element);
  }
}

๋จผ์ €, CompositeComponent์„ ๊ตฌํ˜„ํ•œ ๊ฒƒ์„ ๋ด…์‹œ๋‹ค.

class CompositeComponent {
  constructor(element) {
    this.currentElement = element;
    this.renderedComponent = null;
    this.publicInstance = null;
  }

  getPublicInstance() {
    // For composite components, expose the class instance.
    return this.publicInstance;
  }

  mount() {
    var element = this.currentElement;
    var type = element.type;
    var props = element.props;

    var publicInstance;
    var renderedElement;
    if (isClass(type)) {
      // Component class
      publicInstance = new type(props);
      // Set the props
      publicInstance.props = props;
      // Call the lifecycle if necessary
      if (publicInstance.componentWillMount) {
        publicInstance.componentWillMount();
      }
      renderedElement = publicInstance.render();
    } else if (typeof type === 'function') {
      // Component function
      publicInstance = null;
      renderedElement = type(props);
    }

    // Save the public instance
    this.publicInstance = publicInstance;

    // Instantiate the child internal instance according to the element.
    // It would be a DOMComponent for <div /> or <p />,
    // and a CompositeComponent for <App /> or <Button />:
    var renderedComponent = instantiateComponent(renderedElement);
    this.renderedComponent = renderedComponent;

    // Mount the rendered output
    return renderedComponent.mount();
  }
}

์ด๋Š” ์ด์ „ mountComposite() ๊ตฌํ˜„๊ณผ ํฌ๊ฒŒ ๋‹ค๋ฅด์ง€ ์•Š์ง€๋งŒ,this.currentElement, this.renderedComponent, this.publicInstance ์™€ ๊ฐ™์ด ์—…๋ฐ์ดํŠธ์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ์ •๋ณด๋ฅผ ์ €์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

CompositeComponent์˜ ์ธ์Šคํ„ด์Šค๊ฐ€ ์‚ฌ์šฉ์ž๊ฐ€ ์ œ๊ณตํ•˜๋Š” element.type์˜ ์ธ์Šคํ„ด์Šค์™€ ๋‹ค๋ฅด๋‹ค๋Š” ๊ฒƒ์„ ์ฃผ์˜ํ•ด์ฃผ์„ธ์š”. CompositeComponent๋Š” ์žฌ์กฐ์ •์ž์˜ ์„ธ๋ถ€ ๊ตฌํ˜„ ๋‚ด์šฉ์ด๊ณ , ์‚ฌ์šฉ์ž์—๊ฒŒ๋Š” ๋…ธ์ถœ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž ์ •์˜๋œ class๋Š” element.type๋กœ๋ถ€ํ„ฐ ์–ป๊ณ , CompositeComponent๊ฐ€ ์ด์— ๋Œ€ํ•œ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

ํ˜ผ๋™์„ ๋ง‰๊ธฐ ์œ„ํ•ด, CompositeComponent์™€ DOMComponent์˜ ์ธ์Šคํ„ด์Šค๋ฅผ โ€œ๋‚ด๋ถ€ ์ธ์Šคํ„ด์Šคโ€๋ผ ๋ถ€๋ฆ…๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๋ช‡ ๊ฐ€์ง€ ์˜ค๋ž˜ ์ง€์†๋˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๋‚ด๋ถ€ ์ธ์Šคํ„ด์Šค์™€ ์—ฐ๊ฒฐ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ค์ง ๋ Œ๋”๋Ÿฌ์™€ ์žฌ์กฐ์ •์ž๋งŒ ๋‚ด๋ถ€ ์ธ์Šคํ„ด์Šค๋ฅผ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฐ˜๋ฉด, ์‚ฌ์šฉ์ž ์ •์˜๋œ class์˜ ์ธ์Šคํ„ด์Šค๋ฅผ โ€œ๊ณต๊ฐœ๋œ ์ธ์Šคํ„ด์Šค(public instance)โ€œ๋ผ๊ณ  ๋ถ€๋ฆ…๋‹ˆ๋‹ค. ๊ณต๊ฐœ๋œ ์ธ์Šคํ„ด์Šค๋Š” render()์™€ ์‚ฌ์šฉ์ž๊ฐ€ ์ง์ ‘ ์ž‘์„ฑํ•œ ์—ฌ๋Ÿฌ ๋ฉ”์„œ๋“œ์—์„œ this๋กœ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.

DOMComponent class์˜ mount() ๋ฉ”์„œ๋“œ๋กœ ๋ฆฌํŒฉํ„ฐ๋ง๋œ mountHost() ๋ฉ”์„œ๋“œ ๋˜ํ•œ ๋น„์Šทํ•˜๊ฒŒ ๋ณด์ž…๋‹ˆ๋‹ค.

class DOMComponent {
  constructor(element) {
    this.currentElement = element;
    this.renderedChildren = [];
    this.node = null;
  }

  getPublicInstance() {
    // For DOM components, only expose the DOM node.
    return this.node;
  }

  mount() {
    var element = this.currentElement;
    var type = element.type;
    var props = element.props;
    var children = props.children || [];
    if (!Array.isArray(children)) {
      children = [children];
    }

    // Create and save the node
    var node = document.createElement(type);
    this.node = node;

    // Set the attributes
    Object.keys(props).forEach(propName => {
      if (propName !== 'children') {
        node.setAttribute(propName, props[propName]);
      }
    });

    // Create and save the contained children.
    // Each of them can be a DOMComponent or a CompositeComponent,
    // depending on whether the element type is a string or a function.
    var renderedChildren = children.map(instantiateComponent);
    this.renderedChildren = renderedChildren;

    // Collect DOM nodes they return on mount
    var childNodes = renderedChildren.map(child => child.mount());
    childNodes.forEach(childNode => node.appendChild(childNode));

    // Return the DOM node as mount result
    return node;
  }
}

mountHost()๋กœ ๋ฆฌํŒฉํ„ฐ๋งํ•œ ํ›„์˜ ์ฃผ์š” ์ฐจ์ด์ ์€ this.node์™€ ๋‚ด๋ถ€ DOM ์ปดํฌ๋„ŒํŠธ ์ธ์Šคํ„ด์Šค์™€ ์—ฐ๊ฒฐ๋œ this.renderedChildren์„ ์œ ์ง€ํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํ–ฅํ›„ non-destructive ์—…๋ฐ์ดํŠธ ์ ์šฉ์—๋„ ํ™œ์šฉํ•  ์˜ˆ์ •์ž…๋‹ˆ๋‹ค.

๊ฒฐ๊ณผ์ ์œผ๋กœ, ๋ณตํ•ฉ ๋˜๋Š” ํ˜ธ์ŠคํŠธ์ธ ๊ฐ ๋‚ด๋ถ€ ์ธ์Šคํ„ด์Šค๋Š” ์ด์ œ ์ž์‹ ๋‚ด๋ถ€ ์ธ์Šคํ„ด์Šค๋ฅผ ๊ฐ€๋ฆฌํ‚ต๋‹ˆ๋‹ค. ์ด๋ฅผ ์‹œ๊ฐํ™”ํ•˜๊ธฐ ์œ„ํ•ด ํ•จ์ˆ˜ <App> ์ปดํฌ๋„ŒํŠธ๊ฐ€ <Button> class ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ Œ๋”๋งํ•˜๊ณ  Button class๊ฐ€ <div>๋ฅผ ๋ Œ๋”๋งํ•˜๋Š” ๊ฒฝ์šฐ ๋‚ด๋ถ€ ์ธ์Šคํ„ด์Šค ํŠธ๋ฆฌ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ณด์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

[object CompositeComponent] {
  currentElement: <App />,
  publicInstance: null,
  renderedComponent: [object CompositeComponent] {
    currentElement: <Button />,
    publicInstance: [object Button],
    renderedComponent: [object DOMComponent] {
      currentElement: <div />,
      node: [object HTMLDivElement],
      renderedChildren: []
    }
  }
}

DOM์—์„œ๋Š” <div>๋งŒ ๋ณด์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋‚ด๋ถ€ ์ธ์Šคํ„ด์Šค ํŠธ๋ฆฌ์—๋Š” ๋ณตํ•ฉ์ ์ธ ๊ฒƒ๊ณผ ํ˜ธ์ŠคํŠธ ๋‚ด๋ถ€ ์ธ์Šคํ„ด์Šค๊ฐ€ ๋ชจ๋‘ ํฌํ•จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

๋ณตํ•ฉ ๋‚ด๋ถ€ ์ธ์Šคํ„ด์Šค๋Š” ๋‹ค์Œ์„ ์ €์žฅํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  • ํ˜„์žฌ ์—˜๋ฆฌ๋จผํŠธ
  • ์—˜๋ฆฌ๋จผํŠธ ํƒ€์ž…์ด ํด๋ž˜์Šค๋ผ๋ฉด public ์ธ์Šคํ„ด์Šค
  • ๋‹จ์ผ ๋ Œ๋”๋ง๋œ ๋‚ด๋ถ€ ์ธ์Šคํ„ด์Šค. DOMComponent ๋˜๋Š” CompositeComponent๊ฐ€ ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ˜ธ์ŠคํŠธ ๋‚ด๋ถ€ ์ธ์Šคํ„ด์Šค๋Š” ๋‹ค์Œ์„ ์ €์žฅํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  • ํ˜„์žฌ ์—˜๋ฆฌ๋จผํŠธ
  • DOM ๋…ธ๋“œ
  • ๋ชจ๋“  ์ž์‹ ๋‚ด๋ถ€ ์ธ์Šคํ„ด์Šค. ๊ฐ ์ธ์Šคํ„ด์Šค๋Š” DOMComponent ๋˜๋Š” CompositeComponent์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋” ๋ณต์žกํ•œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ๋‚ด๋ถ€ ์ธ์Šคํ„ด์Šค ํŠธ๋ฆฌ๊ฐ€ ์–ด๋–ป๊ฒŒ ๊ตฌ์„ฑ๋˜๋Š”์ง€ ์ƒ์ƒํ•˜๊ธฐ ์–ด๋ ค์šธ ๊ฒฝ์šฐ, React DevTools๋Š” ํ˜ธ์ŠคํŠธ ์ธ์Šคํ„ด์Šค๋ฅผ ํšŒ์ƒ‰ ๊ทธ๋ฆฌ๊ณ  ๋ณตํ•ฉ ์ธ์Šคํ„ด์Šค๋ฅผ ๋ณด๋ผ์ƒ‰์œผ๋กœ ๊ฐ•์กฐํ•˜๋ฏ€๋กœ ๊ฐ€๊นŒ์šด ๊ทผ์‚ฌ์น˜๋ฅผ ์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

React DevTools tree

๋ฆฌํŒฉํ† ๋ง์„ ์™„๋ฃŒํ•˜๊ธฐ ์œ„ํ•ด ์ „์ฒด ํŠธ๋ฆฌ๋ฅผ ์ปจํ…Œ์ด๋„ˆ ๋…ธ๋“œ์™€ ๊ณต๊ฐœ ์ธ์Šคํ„ด์Šค์— ๋งˆ์šดํŠธํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์†Œ๊ฐœํ•ฉ๋‹ˆ๋‹ค.

function mountTree(element, containerNode) {
  // Create the top-level internal instance
  var rootComponent = instantiateComponent(element);

  // Mount the top-level component into the container
  var node = rootComponent.mount();
  containerNode.appendChild(node);

  // Return the public instance it provides
  var publicInstance = rootComponent.getPublicInstance();
  return publicInstance;
}

var rootEl = document.getElementById('root');
mountTree(<App />, rootEl);

๋งˆ์šดํŠธ ํ•ด์ œ

์ด์ œ ์ž์‹๋“ค๊ณผ DOM ๋…ธ๋“œ๋ฅผ ์œ ์ง€ํ•˜๋Š” ๋‚ด๋ถ€ ์ธ์Šคํ„ด์Šค๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฏ€๋กœ, ๋งˆ์šดํŠธ ํ•ด์ œ๋ฅผ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ณตํ•ฉ ์ปดํฌ๋„ŒํŠธ์˜ ๊ฒฝ์šฐ, ๋งˆ์šดํŠธ ํ•ด์ œ๊ฐ€ ์ƒ๋ช…์ฃผ๊ธฐ ๋ฉ”์„œ๋“œ๋ฅผ ์žฌ๊ท€์ ์œผ๋กœ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.

class CompositeComponent {

  // ...

  unmount() {
    // Call the lifecycle method if necessary
    var publicInstance = this.publicInstance;
    if (publicInstance) {
      if (publicInstance.componentWillUnmount) {
        publicInstance.componentWillUnmount();
      }
    }

    // Unmount the single rendered component
    var renderedComponent = this.renderedComponent;
    renderedComponent.unmount();
  }
}

DOMComponent์˜ ๊ฒฝ์šฐ ๋งˆ์šดํŠธ ํ•ด์ œ๋Š” ๊ฐ ์ž์‹์—๊ฒŒ ๋งˆ์šดํŠธ ํ•ด์ œ๋ฅผ ์ง€์‹œํ•ฉ๋‹ˆ๋‹ค.

class DOMComponent {

  // ...

  unmount() {
    // Unmount all the children
    var renderedChildren = this.renderedChildren;
    renderedChildren.forEach(child => child.unmount());
  }
}

์‹ค์ œ๋กœ DOM ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งˆ์šดํŠธ ํ•ด์ œํ•˜๋ฉด ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๊ฐ€ ์ œ๊ฑฐ๋˜๊ณ  ์บ์‹œ๊ฐ€ ์ผ๋ถ€ ์ง€์›Œ์ง€์ง€๋งŒ ์ด๋Ÿฌํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๋„˜์–ด๊ฐ€๊ฒ ์Šต๋‹ˆ๋‹ค.

์ด์ œ ReactDOM.unmountComponentAtNode()์™€ ์œ ์‚ฌํ•œ unmountTree(containerNode)๋ผ๋Š” ์ƒˆ๋กœ์šด ์ตœ์ƒ์œ„ ํ•จ์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

function unmountTree(containerNode) {
  // Read the internal instance from a DOM node:
  // (This doesn't work yet, we will need to change mountTree() to store it.)
  var node = containerNode.firstChild;
  var rootComponent = node._internalInstance;

  // Unmount the tree and clear the container
  rootComponent.unmount();
  containerNode.innerHTML = '';
}

์ด๊ฒƒ์ด ์ž‘๋™ํ•˜๋ ค๋ฉด DOM ๋…ธ๋“œ์—์„œ ๋‚ด๋ถ€ ๋ฃจํŠธ ์ธ์Šคํ„ด์Šค๋ฅผ ์ฝ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. _internalInstance ์†์„ฑ์„ ๋ฃจํŠธ DOM ๋…ธ๋“œ์— ์ถ”๊ฐ€ํ•˜๋„๋ก mountTree()๋ฅผ ์ˆ˜์ •ํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ mountTree()๋ฅผ ๊ฐ€๋ฅด์ณ ๊ธฐ์กด ํŠธ๋ฆฌ๋ฅผ ์—ฌ๋Ÿฌ ๋ฒˆ ํŒŒ๊ดดํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

function mountTree(element, containerNode) {
  // Destroy any existing tree
  if (containerNode.firstChild) {
    unmountTree(containerNode);
  }

  // Create the top-level internal instance
  var rootComponent = instantiateComponent(element);

  // Mount the top-level component into the container
  var node = rootComponent.mount();
  containerNode.appendChild(node);

  // Save a reference to the internal instance
  node._internalInstance = rootComponent;

  // Return the public instance it provides
  var publicInstance = rootComponent.getPublicInstance();
  return publicInstance;
}

์ด์ œ mountTree() ๋˜๋Š” unmountTree()๋ฅผ ๋ฐ˜๋ณต์ ์œผ๋กœ ์‹คํ–‰ํ•˜๋ฉด ์˜ค๋ž˜๋œ ํŠธ๋ฆฌ๊ฐ€ ์ œ๊ฑฐ๋˜๊ณ  ์ปดํฌ๋„ŒํŠธ์—์„œ componentWillUnmount() ์ƒ๋ช…์ฃผ๊ธฐ ๋ฉ”์„œ๋“œ๊ฐ€ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.

์—…๋ฐ์ดํŠธ

์ด์ „ ์„น์…˜์—์„œ, ๋งˆ์šดํŠธ ํ•ด์ œ๋ฅผ ๊ตฌํ˜„ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๊ฐ๊ฐ์˜ prop ๋ณ€ํ™”๊ฐ€ ์ „์ฒด ํŠธ๋ฆฌ๋ฅผ ๋งˆ์šดํŠธ ํ•ด์ œํ•˜๊ณ  ๋งˆ์šดํŠธํ•œ๋‹ค๋ฉด React๋Š” ๊ทธ๋‹ค์ง€ ์œ ์šฉํ•˜์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์กฐ์ •์ž์˜ ๋ชฉํ‘œ๋Š” DOM๊ณผ ์ƒํƒœ๋ฅผ ๋ณด์ „ํ•˜๊ธฐ ์œ„ํ•ด ๊ฐ€๋Šฅํ•œ ๊ฒฝ์šฐ ๊ธฐ์กด ์ธ์Šคํ„ด์Šค๋ฅผ ์žฌ์‚ฌ์šฉ ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

var rootEl = document.getElementById('root');

mountTree(<App />, rootEl);
// Should reuse the existing DOM:
mountTree(<App />, rootEl);

๋‚ด๋ถ€ ์ธ์Šคํ„ด์Šค ๊ณ„์•ฝ์„ ๋ฉ”์„œ๋“œ ํ•˜๋‚˜๋ฅผ ์ถ”๊ฐ€ํ•ด์„œ ํ™•์žฅํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. mount()์™€ unmount()์™ธ์—๋„ , DOMComponent CompositeComponent ๋ชจ๋‘ receive(nextElement)๋ผ๊ณ  ๋ถˆ๋ฆฌ๋Š” ์ƒˆ๋กœ์šด ๋ฉ”์„œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.

class CompositeComponent {
  // ...

  receive(nextElement) {
    // ...
  }
}

class DOMComponent {
  // ...

  receive(nextElement) {
    // ...
  }
}

nextElement์— ์˜ํ•ด ์ œ๊ณต๋œ ์„ค๋ช…์„ ํ†ตํ•ด ์ปดํฌ๋„ŒํŠธ(๋˜ํ•œ ์–ด๋– ํ•œ ์ž์‹)๋ฅผ ์ตœ์‹  ์ƒํƒœ๋กœ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ํ•„์š”ํ•œ ๋ชจ๋“  ๊ฒƒ์„ ํ•˜๋Š”๊ฒŒ ์ด ๋ฉ”์„œ๋“œ์˜ ์ผ์ž…๋‹ˆ๋‹ค.

์‹ค์ œ๋กœ ์ผ์–ด๋‚˜๋Š” ์ผ์€ ๋‚ด๋ถ€ ํŠธ๋ฆฌ๋ฅผ ๋ฐ˜๋ณต์ ์œผ๋กœ ์ˆœํšŒํ•˜๊ณ  ๊ฐ ๋‚ด๋ถ€ ์ธ์Šคํ„ด์Šค๊ฐ€ ์—…๋ฐ์ดํŠธ๋ฅผ ๋ฐ›๋„๋ก ํ•˜๋Š” ๊ฒƒ์ด์ง€๋งŒ, ์ด ๋ถ€๋ถ„์€ ์ข…์ข… โ€œ๊ฐ€์ƒ DOM ๋น„๊ตโ€๋กœ ์„ค๋ช…๋ฉ๋‹ˆ๋‹ค.

๋ณตํ•ฉ ์ปดํฌ๋„ŒํŠธ์˜ ์—…๋ฐ์ดํŠธ

๋ณตํ•ฉ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ƒˆ๋กœ์šด ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ๋ฐ›์œผ๋ฉด componentWillUpdate() ์ƒ๋ช…์ฃผ๊ธฐ ๋ฉ”์„œ๋“œ๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

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

class CompositeComponent {

  // ...

  receive(nextElement) {
    var prevProps = this.currentElement.props;
    var publicInstance = this.publicInstance;
    var prevRenderedComponent = this.renderedComponent;
    var prevRenderedElement = prevRenderedComponent.currentElement;

    // Update *own* element
    this.currentElement = nextElement;
    var type = nextElement.type;
    var nextProps = nextElement.props;

    // Figure out what the next render() output is
    var nextRenderedElement;
    if (isClass(type)) {
      // Component class
      // Call the lifecycle if necessary
      if (publicInstance.componentWillUpdate) {
        publicInstance.componentWillUpdate(nextProps);
      }
      // Update the props
      publicInstance.props = nextProps;
      // Re-render
      nextRenderedElement = publicInstance.render();
    } else if (typeof type === 'function') {
      // Component function
      nextRenderedElement = type(nextProps);
    }

    // ...

๊ทธ ๋‹ค์Œ, ๋ Œ๋”๋ง๋œ ์—˜๋ฆฌ๋จผํŠธ์˜ type์„ ์‚ดํŽด ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋งˆ์ง€๋ง‰ ๋ Œ๋”๋ง ์ดํ›„ type์ด ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์•˜๋‹ค๋ฉด ์•„๋ž˜ ์ปดํฌ๋„ŒํŠธ๋„ ์—…๋ฐ์ดํŠธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, ์ฒ˜์Œ์— <Button color="red" />๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ณ  ๋‘ ๋ฒˆ์งธ๋กœ <Button color="blue" />๋ฅผ ๋ฐ˜ํ™˜ํ–ˆ๋‹ค๋ฉด, ๋Œ€์‘๋˜๋Š” ๋‚ด๋ถ€ ์ธ์Šคํ„ด์Šค์—๊ฒŒ ๋‹ค์Œ ์—˜๋ฆฌ๋จผํŠธ๋ฅผ receive()ํ•˜๋ผ๊ณ  ๋งํ•ด์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    // ...

    // If the rendered element type has not changed,
    // reuse the existing component instance and exit.
    if (prevRenderedElement.type === nextRenderedElement.type) {
      prevRenderedComponent.receive(nextRenderedElement);
      return;
    }

    // ...

๊ทธ๋Ÿฌ๋‚˜, ๋‹ค์Œ ๋ Œ๋”๋ง๋œ ์—˜๋ฆฌ๋จผํŠธ๊ฐ€ ์ด์ „์— ๋ Œ๋”๋ง๋œ ์—˜๋ฆฌ๋จผํŠธ์™€ ๋‹ค๋ฅธ type์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๋ฉด, ์šฐ๋ฆฌ๋Š” ๋‚ด๋ถ€ ์ธ์Šคํ„ด์Šค๋ฅผ ์—…๋ฐ์ดํŠธํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. <button>์€ <input>์ด ๋  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

๋Œ€์‹ ์—, ๊ธฐ์กด ๋‚ด๋ถ€ ์ธ์Šคํ„ด์Šค๋ฅผ ๋งˆ์šดํŠธ ํ•ด์ œ ํ•˜๊ณ  ๋ Œ๋”๋ง๋œ ์—˜๋ฆฌ๋จผํŠธ ํƒ€์ž…์— ํ•ด๋‹นํ•˜๋Š” ์ƒˆ ์ธ์Šคํ„ด์Šค๋ฅผ ๋งˆ์šดํŠธ ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์ด์ „์— <button />์„ ๋ Œ๋”๋งํ•œ ์ปดํฌ๋„ŒํŠธ๊ฐ€ <input />์„ ๋ Œ๋”๋งํ•  ๋•Œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ฉ๋‹ˆ๋‹ค.

    // ...

    // If we reached this point, we need to unmount the previously
    // mounted component, mount the new one, and swap their nodes.

    // Find the old node because it will need to be replaced
    var prevNode = prevRenderedComponent.getHostNode();

    // Unmount the old child and mount a new child
    prevRenderedComponent.unmount();
    var nextRenderedComponent = instantiateComponent(nextRenderedElement);
    var nextNode = nextRenderedComponent.mount();

    // Replace the reference to the child
    this.renderedComponent = nextRenderedComponent;

    // Replace the old node with the new one
    // Note: this is renderer-specific code and
    // ideally should live outside of CompositeComponent:
    prevNode.parentNode.replaceChild(nextNode, prevNode);
  }
}

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

์—˜๋ฆฌ๋จผํŠธ๋ฅผ ๋ฐ›๋Š” ๋Œ€์‹  ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋‹ค์‹œ ๋งˆ์šดํŠธํ•˜๋Š” ๋˜ ๋‹ค๋ฅธ ์กฐ๊ฑด์ด ์žˆ๋Š”๋ฐ, ์—˜๋ฆฌ๋จผํŠธ์˜ key๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ์ž…๋‹ˆ๋‹ค. ์ด๋ฏธ ๋ณต์žกํ•œ ์ž์Šต์„œ๋ฅผ ๋” ๋ณต์žกํ•˜๊ฒŒ ๋งŒ๋“ค๊ธฐ ๋•Œ๋ฌธ์— ์ด ๋ฌธ์„œ์—์„œ key ์ฒ˜๋ฆฌ์— ๋Œ€ํ•ด์„œ๋Š” ๋…ผ์˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

ํŠน์ • ํ”Œ๋žซํผ ๊ด€๋ จ ๋…ธ๋“œ๋ฅผ ์ฐพ์•„ ์—…๋ฐ์ดํŠธํ•˜๋Š” ๋™์•ˆ ๊ต์ฒดํ•  ์ˆ˜ ์žˆ๋„๋ก ๋‚ด๋ถ€ ์ธ์Šคํ„ด์Šค ๊ณ„์•ฝ์— getHostNode()๋ผ๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ํ•œ๋‹ค๋Š” ์ ์„ ์ฃผ์˜ํ•ด์ฃผ์„ธ์š”. ๊ตฌํ˜„์€ ๋‘ ํด๋ž˜์Šค ๋ชจ๋‘์—์„œ ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค.

class CompositeComponent {
  // ...

  getHostNode() {
    // Ask the rendered component to provide it.
    // This will recursively drill down any composites.
    return this.renderedComponent.getHostNode();
  }
}

class DOMComponent {
  // ...

  getHostNode() {
    return this.node;
  }
}

ํ˜ธ์ŠคํŠธ ์ปดํฌ๋„ŒํŠธ ์—…๋ฐ์ดํŠธ

DOMComponent์™€ ๊ฐ™์€ ํ˜ธ์ŠคํŠธ ์ปดํฌ๋„ŒํŠธ ๊ตฌํ˜„์€ ๋‹ค๋ฅด๊ฒŒ ์—…๋ฐ์ดํŠธ ๋ฉ๋‹ˆ๋‹ค. ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ์ˆ˜์‹ ํ•  ๋•Œ ํŠน์ • ํ”Œ๋žซํผ ๊ด€๋ จ ๋ทฐ๋ฅผ ์—…๋ฐ์ดํŠธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. React DOM์˜ ๊ฒฝ์šฐ DOM ํŠน์„ฑ์„ ์—…๋ฐ์ดํŠธ ํ•˜๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

class DOMComponent {
  // ...

  receive(nextElement) {
    var node = this.node;
    var prevElement = this.currentElement;
    var prevProps = prevElement.props;
    var nextProps = nextElement.props;
    this.currentElement = nextElement;

    // Remove old attributes.
    Object.keys(prevProps).forEach(propName => {
      if (propName !== 'children' && !nextProps.hasOwnProperty(propName)) {
        node.removeAttribute(propName);
      }
    });
    // Set next attributes.
    Object.keys(nextProps).forEach(propName => {
      if (propName !== 'children') {
        node.setAttribute(propName, nextProps[propName]);
      }
    });

    // ...

๊ทธ๋ฆฌ๊ณ  ๋‚˜์„œ ํ˜ธ์ŠคํŠธ ์ปดํฌ๋„ŒํŠธ๋Š” ์ž์‹๋“ค์„ ์—…๋ฐ์ดํŠธ ํ•  ํ•„์š”๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ณตํ•ฉ ์ปดํฌ๋„ŒํŠธ์™€ ๋‹ค๋ฅด๊ฒŒ ๋‘˜ ์ด์ƒ์˜ ์ž์‹์ด ํฌํ•จ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹จ์ˆœํ™”๋œ ์˜ˆ์‹œ์—์„œ ๋‚ด๋ถ€ ์ธ์Šคํ„ด์Šค ๋ฐฐ์—ด์„ ์‚ฌ์šฉํ•˜๋ฉฐ, ์ˆ˜์‹ ๋œ type๊ณผ ์ด์ „ type์˜ ์ผ์น˜ ์—ฌ๋ถ€์— ๋”ฐ๋ผ ๋‚ด๋ถ€ ์ธ์Šคํ„ด์Šค๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๊ฑฐ๋‚˜ ๊ต์ฒดํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์ˆœํšŒํ•ฉ๋‹ˆ๋‹ค. ์‹ค์ œ ์žฌ์กฐ์ •์ž๋Š” ์‚ฝ์ž…๊ณผ ์‚ญ์ œ ์™ธ์— ์—˜๋ฆฌ๋จผํŠธ์˜ key๋ฅผ ๊ฐ€์ง„ ๋’ค ๋ณ€๊ฒฝ ์—ฌ๋ถ€๋ฅผ ์ถ”์ ํ•˜์ง€๋งŒ ์—ฌ๊ธฐ์„œ๋Š” ๊ด€๋ จ ์ฝ”๋“œ๋ฅผ ์ƒ๋žตํ–ˆ์Šต๋‹ˆ๋‹ค.

๋ฆฌ์ŠคํŠธ์—์„œ ์ž์‹์— ๋Œ€ํ•œ DOM ์—ฐ์‚ฐ์„ ์ˆ˜์ง‘ํ•˜์—ฌ ์ผ๊ด„์ ์œผ๋กœ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

    // ...

    // These are arrays of React elements:
    var prevChildren = prevProps.children || [];
    if (!Array.isArray(prevChildren)) {
      prevChildren = [prevChildren];
    }
    var nextChildren = nextProps.children || [];
    if (!Array.isArray(nextChildren)) {
      nextChildren = [nextChildren];
    }
    // These are arrays of internal instances:
    var prevRenderedChildren = this.renderedChildren;
    var nextRenderedChildren = [];

    // As we iterate over children, we will add operations to the array.
    var operationQueue = [];

    // Note: the section below is extremely simplified!
    // It doesn't handle reorders, children with holes, or keys.
    // It only exists to illustrate the overall flow, not the specifics.

    for (var i = 0; i < nextChildren.length; i++) {
      // Try to get an existing internal instance for this child
      var prevChild = prevRenderedChildren[i];

      // If there is no internal instance under this index,
      // a child has been appended to the end. Create a new
      // internal instance, mount it, and use its node.
      if (!prevChild) {
        var nextChild = instantiateComponent(nextChildren[i]);
        var node = nextChild.mount();

        // Record that we need to append a node
        operationQueue.push({type: 'ADD', node});
        nextRenderedChildren.push(nextChild);
        continue;
      }

      // We can only update the instance if its element's type matches.
      // For example, <Button size="small" /> can be updated to
      // <Button size="large" /> but not to an <App />.
      var canUpdate = prevChildren[i].type === nextChildren[i].type;

      // If we can't update an existing instance, we have to unmount it
      // and mount a new one instead of it.
      if (!canUpdate) {
        var prevNode = prevChild.getHostNode();
        prevChild.unmount();

        var nextChild = instantiateComponent(nextChildren[i]);
        var nextNode = nextChild.mount();

        // Record that we need to swap the nodes
        operationQueue.push({type: 'REPLACE', prevNode, nextNode});
        nextRenderedChildren.push(nextChild);
        continue;
      }

      // If we can update an existing internal instance,
      // just let it receive the next element and handle its own update.
      prevChild.receive(nextChildren[i]);
      nextRenderedChildren.push(prevChild);
    }

    // Finally, unmount any children that don't exist:
    for (var j = nextChildren.length; j < prevChildren.length; j++) {
      var prevChild = prevRenderedChildren[j];
      var node = prevChild.getHostNode();
      prevChild.unmount();

      // Record that we need to remove the node
      operationQueue.push({type: 'REMOVE', node});
    }

    // Point the list of rendered children to the updated version.
    this.renderedChildren = nextRenderedChildren;

    // ...

๋งˆ์ง€๋ง‰ ๋‹จ๊ณ„๋กœ, DOM ์—ฐ์‚ฐ์„ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ, ์‹ค์ œ ์žฌ์กฐ์ •์ž ์ฝ”๋“œ๋Š” ์ด๋™๋„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋งค์šฐ ๋ณต์žกํ•ฉ๋‹ˆ๋‹ค.

    // ...

    // Process the operation queue.
    while (operationQueue.length > 0) {
      var operation = operationQueue.shift();
      switch (operation.type) {
      case 'ADD':
        this.node.appendChild(operation.node);
        break;
      case 'REPLACE':
        this.node.replaceChild(operation.nextNode, operation.prevNode);
        break;
      case 'REMOVE':
        this.node.removeChild(operation.node);
        break;
      }
    }
  }
}

๊ทธ๋ฆฌ๊ณ  ๊ทธ๊ฒƒ์€ ํ˜ธ์ŠคํŠธ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๊ธฐ ์œ„ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ตœ์ƒ์œ„ ์—…๋ฐ์ดํŠธ

์ด์ œ CompositeComponent์™€ DOMComponent ๋ชจ๋‘ receive(nextElement) ๋ฉ”์„œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•˜๋ฏ€๋กœ ์—˜๋ฆฌ๋จผํŠธ type์ด ์ด์ „๊ณผ ๊ฐ™์„ ๋•Œ ์‚ฌ์šฉํ•˜๋„๋ก ์ตœ์ƒ์œ„ mountTree() ํ•จ์ˆ˜๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

function mountTree(element, containerNode) {
  // Check for an existing tree
  if (containerNode.firstChild) {
    var prevNode = containerNode.firstChild;
    var prevRootComponent = prevNode._internalInstance;
    var prevElement = prevRootComponent.currentElement;

    // If we can, reuse the existing root component
    if (prevElement.type === element.type) {
      prevRootComponent.receive(element);
      return;
    }

    // Otherwise, unmount the existing tree
    unmountTree(containerNode);
  }

  // ...

}

์ด์ œ ๋™์ผํ•œ ํƒ€์ž…์œผ๋กœ mountTree()๋ฅผ ๋‘ ๋ฒˆ ํ˜ธ์ถœํ•ด๋„ ํŒŒ๊ดด์ ์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

var rootEl = document.getElementById('root');

mountTree(<App />, rootEl);
// Reuses the existing DOM:
mountTree(<App />, rootEl);

These are the basics of how React works internally.

์šฐ๋ฆฌ๊ฐ€ ๋†“์น˜๊ณ  ๊ฐ„ ๊ฒƒ๋“ค

์ด ๋ฌธ์„œ๋Š” ์‹ค์ œ ์ฝ”๋“œ๋ฒ ์ด์Šค์— ๋น„ํ•ด ๋‹จ์ˆœํ•ฉ๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ๋‹ค๋ฃจ์ง€ ์•Š์€ ๋ช‡ ๊ฐ€์ง€ ์ค‘์š”ํ•œ ์ธก๋ฉด๋“ค์ด ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์ปดํฌ๋„ŒํŠธ๋Š” null์„ ๋ Œ๋”๋งํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์žฌ์กฐ์ •์ž๋Š” ๋ฐฐ์—ด ๋ฐ ๋ Œ๋”๋ง๋œ ์ถœ๋ ฅ์—์„œ โ€œ๋นˆ ์Šฌ๋กฏโ€์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์žฌ์กฐ์ •์ž๋Š” ๋˜ํ•œ ์—˜๋ฆฌ๋จผํŠธ์—์„œ key๋ฅผ ์ฝ๊ณ , ์ด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐฐ์—ด์˜ ์—˜๋ฆฌ๋จผํŠธ์™€ ์ผ์น˜ํ•˜๋Š” ๋‚ด๋ถ€ ์ธ์Šคํ„ด์Šค๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. ์‹ค์ œ React ๊ตฌํ˜„์˜ ๋งŽ์€ ๋ณต์žก์„ฑ์€ ์ด์™€ ๊ด€๋ จ์ด ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋ณตํ•ฉ ๋ฐ ํ˜ธ์ŠคํŠธ ๋‚ด๋ถ€ ์ธ์Šคํ„ด์Šค class ์™ธ์—๋„ โ€œtextโ€ ๋ฐ โ€œemptyโ€ ์ปดํฌ๋„ŒํŠธ์— ๋Œ€ํ•œ class๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ํ…์ŠคํŠธ ๋…ธ๋“œ์™€ null์„ ๋ Œ๋”๋งํ•ด์„œ ์–ป๋Š” โ€œempty slotsโ€์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.
  • ๋ Œ๋”๋Ÿฌ๋Š” ์ฃผ์ž…์„ ์‚ฌ์šฉํ•˜์—ฌ ์žฌ์กฐ์ •์ž์—๊ฒŒ ํ˜ธ์ŠคํŠธ ๋‚ด๋ถ€ class๋ฅผ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, React DOM์€ ์žฌ์กฐ์ •์ž์—๊ฒŒ ํ˜ธ์ŠคํŠธ ๋‚ด๋ถ€ ์ธ์Šคํ„ด์Šค ๊ตฌํ˜„์œผ๋กœ ReactDOMComponent๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ์ง€์‹œํ•ฉ๋‹ˆ๋‹ค.
  • ์ž์‹ ๋ชฉ๋ก์„ ์—…๋ฐ์ดํŠธํ•˜๋Š” ๋…ผ๋ฆฌ๋Š” React DOM๊ณผ React Native์—์„œ ํ˜ธ์ŠคํŠธ ๋‚ด๋ถ€ ์ธ์Šคํ„ด์Šค class ๊ตฌํ˜„์— ์‚ฌ์šฉ๋˜๋Š” ReactMultiChild๋ผ๋Š” mixin์œผ๋กœ ์ถ”์ถœ๋ฉ๋‹ˆ๋‹ค.
  • ์žฌ์กฐ์ •์ž๋Š” ๋ณตํ•ฉ ์ปดํฌ๋„ŒํŠธ์˜ setState()์— ๋Œ€ํ•œ ์ง€์›๋„ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ ๋‚ด๋ถ€์˜ ์—ฌ๋Ÿฌ ์—…๋ฐ์ดํŠธ๊ฐ€ ๋‹จ์ผ ์—…๋ฐ์ดํŠธ๋กœ ์ผ๊ด„ ์ฒ˜๋ฆฌ๋ฉ๋‹ˆ๋‹ค.
  • ์žฌ์กฐ์ •์ž๋Š” ๋˜ํ•œ ๋ณตํ•ฉ ์ปดํฌ๋„ŒํŠธ ๋ฐ ํ˜ธ์ŠคํŠธ ๋…ธ๋“œ์— ref๋ฅผ ์—ฐ๊ฒฐ ๋ฐ ๋ถ„๋ฆฌํ•˜๋Š” ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  • componentDidMount() ๋ฐ componentDidUpdate()์™€ ๊ฐ™์ด DOM์ด ์ค€๋น„๋œ ํ›„ ํ˜ธ์ถœ๋˜๋Š” ์ƒ๋ช…์ฃผ๊ธฐ ๋ฉ”์„œ๋“œ๋Š” โ€œ์ฝœ๋ฐฑ ํโ€๋กœ ์ˆ˜์ง‘๋˜์–ด ๋‹จ์ผ ๋ฐฐ์น˜๋กœ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.
  • React๋Š” ํ˜„์žฌ ์—…๋ฐ์ดํŠธ์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ โ€œํŠธ๋žœ์žญ์…˜โ€์ด๋ผ๊ณ  ํ•˜๋Š” ๋‚ด๋ถ€ ๊ฐ์ฒด์— ๋„ฃ์Šต๋‹ˆ๋‹ค. ํŠธ๋žœ์žญ์…˜์€ ๋ณด๋ฅ˜ ์ค‘์ธ ์ƒ๋ช…์ฃผ๊ธฐ ๋ฉ”์„œ๋“œ ๋Œ€๊ธฐ์—ด์˜ ์ถ”์ , ํ˜„์žฌ DOM ์ค‘์ฒฉ์— ๋Œ€ํ•œ ๊ฒฝ๊ณ  ๋ฐ ํŠน์ • ์—…๋ฐ์ดํŠธ์— โ€œ์ „์—ญ์ ์ธโ€ ๋‹ค๋ฅธ ๋ชจ๋“  ๊ฒƒ์„ ์ถ”์ ํ•˜๋Š” ๋ฐ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ ํŠธ๋žœ์žญ์…˜๋Š” ์—…๋ฐ์ดํŠธ ํ›„ React๊ฐ€ ๋ชจ๋“  ๊ฒƒ์„ ์ •๋ฆฌํ•˜๋„๋ก ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด React DOM์—์„œ ์ œ๊ณตํ•˜๋Š” ํŠธ๋žœ์žญ์…˜ class๋Š” ์—…๋ฐ์ดํŠธ ํ›„ ์ž…๋ ฅ ์„ ํƒ์„ ๋ณต์›ํ•ฉ๋‹ˆ๋‹ค.

์ฝ”๋“œ์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๊ธฐ

  • ReactMount๋Š” ์ด ์ž์Šต์„œ์—์„œ mountTree() ๋ฐ unmountTree()์™€ ๊ฐ™์€ ์ฝ”๋“œ๊ฐ€ ์‚ฌ์šฉ๋˜๋Š” ๊ณณ์ž…๋‹ˆ๋‹ค. ์ตœ์ƒ์œ„ ์ปดํฌ๋„Œ์ธ ์˜ ๋งˆ์šดํŠธ๊ณผ ๋งˆ์šดํŠธ ํ•ด์ œ์„ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ReactNativeMount ๋Š” React Native ์•„๋‚ ๋กœ๊ทธ์ž…๋‹ˆ๋‹ค.
  • ReactDOMComponent๋Š” ๋ณธ ์ž์Šต์„œ์˜ DOMComponent์™€ ๋™๋“ฑํ•ฉ๋‹ˆ๋‹ค. React DOM ๋ Œ๋”๋Ÿฌ์— ๋Œ€ํ•œ ํ˜ธ์ŠคํŠธ ์ปดํฌ๋„ŒํŠธ class๋ฅผ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค. ReactNativeBaseComponent๋Š” React Native ์•„๋‚ ๋กœ๊ทธ ์ž…๋‹ˆ๋‹ค.
  • ReactCompositeComponent๋Š” ๋ณธ ์ž์Šต์„œ์˜ CompositeComponent์™€ ๋™๋“ฑํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž ์ •์˜ ์ปดํฌ๋„ŒํŠธ ํ˜ธ์ถœ ๋ฐ ์ƒํƒœ ์œ ์ง€ ๊ด€๋ฆฌ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
  • instantiateReactComponent์—๋Š” ์—˜๋ฆฌ๋จผํŠธ์— ๋Œ€ํ•ด ๊ตฌ์„ฑํ•  ์˜ฌ๋ฐ”๋ฅธ ๋‚ด๋ถ€ ์ธ์Šคํ„ด์Šค class๋ฅผ ์„ ํƒํ•˜๋Š” ์Šค์œ„์น˜๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์ž์Šต์„œ์—์„œ๋Š” instantiateComponent()์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.
  • ReactReconciler๋Š” mountComponent(), receiveComponent()๋ฐ unmountComponent() ๋ฉ”์„œ๋“œ๊ฐ€ ์žˆ๋Š” wrapper์ž…๋‹ˆ๋‹ค. ๋‚ด๋ถ€ ์ธ์Šคํ„ด์Šค์— ๋Œ€ํ•œ ๊ธฐ๋ณธ ๊ตฌํ˜„์„ ํ˜ธ์ถœํ•˜์ง€๋งŒ, ๋˜ํ•œ ๋ชจ๋“  ๋‚ด๋ถ€ ์ธ์Šคํ„ด์Šค ๊ตฌํ˜„์— ์˜ํ•ด ๊ณต์œ ๋˜๋Š” ๊ทธ๋“ค ์ฃผ๋ณ€์˜ ์ผ๋ถ€ ์ฝ”๋“œ๋ฅผ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค.
  • ReactChildReconciler๋Š” ์ž์‹์˜ ์—˜๋ฆฌ๋จผํŠธ key์— ๋”ฐ๋ผ ์ž์‹์„ ๋งˆ์šดํŠธ, ์—…๋ฐ์ดํŠธ ๋ฐ ๋งˆ์šดํŠธ ํ•ด์ œํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.
  • ReactMultiChild๋Š” ์ž์‹ ์‚ฝ์ž…, ์‚ญ์ œ ๋ฐ ๋ Œ๋”๋Ÿฌ์™€ ๋…๋ฆฝ์ ์œผ๋กœ ์ด๋™ํ•˜๊ธฐ ์œ„ํ•œ ์ž‘์—… ๋Œ€๊ธฐ์—ด ์ฒ˜๋ฆฌ๋ฅผ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.
  • ๋ ˆ๊ฑฐ์‹œ๋ฅผ ์œ„ํ•ด react codebase์— mount(), receive() ๋ฐ unmount()๋ฅผ ์‹ค์ œ๋กœ ๊ฐ๊ฐ mountComponent(), receiveComponent(), unmountComponent()๋ผ๊ณ  ๋ถˆ๋Ÿฌ์ง€์ง€๋งŒ, ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ๋ฐ›์Šต๋‹ˆ๋‹ค.
  • ๋‚ด๋ถ€ ์ธ์Šคํ„ด์Šค์˜ ์†์„ฑ์€ _currentElement์™€ ๊ฐ™์ด ๋ฐ‘์ค„๋กœ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค. ์ฝ”๋“œ๋ฒ ์ด์Šค ์ „์ฒด์— ๊ฑธ์ณ ์ฝ๊ธฐ ์ „์šฉ ํผ๋ธ”๋ฆญ ํ•„๋“œ๋กœ ๊ฐ„์ฃผ๋ฉ๋‹ˆ๋‹ค.

๋ฏธ๋ž˜์˜ ๋ฐฉํ–ฅ

์Šคํƒ ์žฌ์กฐ์ •์ž๋Š” ์ž‘์—…์„ ์ค‘๋‹จํ•˜๊ฑฐ๋‚˜ ์ฒญํฌ๋กœ ๋ถ„ํ• ํ•  ์ˆ˜ ์—†๋Š” ๊ฒƒ๊ณผ ๊ฐ™์€ ํƒ€๊ณ ๋‚œ ํ•œ๊ณ„๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์™„์ „ํžˆ ๋‹ค๋ฅธ ์•„ํ‚คํ…์ฒ˜๋ฅผ ๊ฐ€์ง„ ์ƒˆ๋กœ์šด Fiber ์žฌ์กฐ์ •์ž์— ๋Œ€ํ•œ ์ž‘์—…์ด ์ง„ํ–‰ ์ค‘์ž…๋‹ˆ๋‹ค. ํ–ฅํ›„, ์Šคํƒ ์žฌ์กฐ์ •์ž๋ฅผ ์ด๊ฒƒ์œผ๋กœ ๋Œ€์ฒดํ•˜๋ ค๊ณ  ํ•˜์ง€๋งŒ, ํ˜„์žฌ๋Š” ํ”ผ์ณ ํŒจ๋ฆฌํ‹ฐ์™€๋Š” ๊ฑฐ๋ฆฌ๊ฐ€ ๋ฉ‰๋‹ˆ๋‹ค.

๋‹ค์Œ ๋‹จ๊ณ„

๋‹ค์Œ ์„น์…˜์„ ์ฝ๊ณ  React ๊ฐœ๋ฐœ์— ์‚ฌ์šฉํ•˜๋Š” ์„ค๊ณ„ ์›์น™์— ๋Œ€ํ•ด ์•Œ์•„๋ด…์‹œ๋‹ค.

Is this page useful?Edit this page