프론트엔드 첫걸음

김민태 프론트엔드 강의 - React 만들기 본문

개발 공부/React

김민태 프론트엔드 강의 - React 만들기

차정 2023. 3. 11. 12:27
export function createDOM(node) {
  if (typeof node === 'string') {
    return document.createTextNode(node);
  }

  const element = document.createElement(node.tag);

  Object.entries(node.props)
    .forEach(([name, value]) => element.setAttribute(name, value));

  node.children
    .map(createDOM)
    .forEach(element.appendChild.bind(element));

  return element;
}

export function createElement(tag, props, ...children) {
  return { tag, props, children };
}

export function render(vdom, container) {
  container.appendChild(createDOM(vdom));
}

 

 

/* @jsx createElement */
const vdom2 = <p>
  <h1>React 만들기</h1>
  <ul>
    <li style="color:red">첫 번째 아이템</li>
    <li style="color:blue">두 번째 아이템</li>
    <li style="color:green">세 번째 아이템</li>
  </ul>
</p>;

 

 

 

  • Babel이 JSX를 함수 호출로 변환한다.
    • JSX는 실제로 특정 함수(createElement) 호출 코드로 변환됨.
    • 예를 들어  const vdom2 = <p>Hello</p> 를 Babel이 변환하면
      const vdom2 = createElement("p", null, "Hello");
    • @jsx 를 사용해 React.createElement를 대신 커스텀 createElement 함수를 호출하도록 설정할 수 있음.
  • @jsx createElement를 사용해 JSX 변환을 커스텀할 수 있다.
    • /* @jsx createElement */ 주석을 추가하면 JSX 변환 시 React.createElement 대신 우리가 만든 createElement를 호출하도록 Babel이 변환해줌.
    • 이 방식으로 React 없이 직접 JSX를 사용할 수 있음.
  • JSX는 그냥 JavaScript가 아니라 런타임에서 Babel이 React.createElement로 변환하는 것.
    • JSX는 브라우저에서 실행할 수 없는 문법이라 Babel이 변환해 줘야 한다.
    • Babel이 JSX를 변환할 때 기본적으로 React.createElement를 호출하도록 변환한다. (@jsx)
    • React.createElement를 쓰려면 React가 import되어 있어야 한다.

JSX 코드

import React from "react"; /* React.createElement가 동작해야하므로 import필요*/

const element = <h1>Hello</h1>;

 

바벨 변환결과

const element = React.createElement("h1", null, "Hello");

 

 

  • React에서 컴포넌트는 반드시 함수여야 하고, 대문자로 시작해야 한다.
    이 경우 Babel이 내부적으로 대문자로 시작하는 JSX 태그를 일반 문자열이 아니라 JavaScript 변수(컴포넌트)로 취급하여 React.createElement를 호출한다.
export function createElement(tag, props, ...children) {
  props = props || {};  // props가 null이면 빈 객체로 설정

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

 

  

  • tag가 함수 컴포넌트인지 확인 (typeof tag === 'function').
      • 함수 컴포넌트 라면 tag(props)를 호출하여 실행 결과를 반환
  • children이 1개면 단일 값으로 전달, 2개 이상이면 배열로 전달.
    • <Title>이름</Title>
    • <Title><Item>1</Item><Item>2</Item></Title> 구분