본문 바로가기
Language & Library/JS & TS

[JavaScript] Vanilla JS로 React 만들기

by 미네마네모 2020. 9. 9.

시작하기 전에...

Vanilla JS로 Virtual DOM을 랜더링 하는 간단한 유사 React를 만들어보려고 한다.


우아한 테크러닝 3기 (TypeScript & React)에서 김민태님의 강좌를 참고하였습니다.

글을 보기 전에 Virtual DOM, JSX에 대한 개념을 익히고 읽기를 권장 합니다.

기본 React App 만들기

우측의 결과를 가져오는 React Example App을 작성하였습니다. (github commit 바로가기)

JS로 우측 앱을 React의 Virtual DOM을 구현하면서 출력하는 프로그램을 작성해 보겠습니다.

React Virtual DOM 분석

위 사진은 React Component를 console.log로 출력한 결과 입니다.

해당 결과를 기반으로 virtualDOM의 ProtoType을 아래와 같이 만들었습니다.
const virtualDOM = {
  type: "ul",
  props: {},
  children: [
    { type: "li", props: { className: "item" }, children: "React" },
    { type: "li", props: { className: "item" }, children: "Redux" },
    { type: "li", props: { className: "item" }, children: "TypeScript" },
    { type: "li", props: { className: "item" }, children: "mobx" },
  ]
};

Virtual DOM 생성 함수(createElement)

babel로 JSX 분석

우측 바로가기 누르면 해당 사이트로 이동합니다.(바로가기)

좌측의 JSX 문법이 babel로 JS로 Transpile된 결과는 우측 입니다.

JSX는 React DOM을 좀더 쉽게 표현하게 해주는 문법 입니다.

기본적으로 React DOM을 생성할 때는 React.createElement를 이용합니다.

React.createElement 확인

function createElement(type, props = {}, ...children) {
  // type이 funtion인 경우 예외 처리
  if (typeof type === "function") {
    return type.apply(null, [props, ...children]);
  }

  return { type, props, children };
}
React.createElement는 type, props, children이라는 parameter를 가집니다.

- type : element의 tag
- props : React DOM의 인자
- children : React DOM의 하위 React DOM들의 배열

아래는 상단에서 정의한 virtual DOM ProtoType을 생성하는 함수 코드 입니다.

(github commit 바로가기)

JSX 템플릿 (React.createElement > createElement)

 

React.createElement를 createElement로 대체

/** @jsx createElement */

위의 주석을 소스 최상단에 입력하면 JSX 문법에서 React.createElement는 createElement로 교체 된다.

따라서 위에서 만든 createElement 함수를 사용할 수 있다.

(github commit 바로가기)

* 참고 사이트 : 바로가기


랜더링 함수(render, renderElement)

 

function renderElement(node) {
  // type에 해당하는 element를 생성.
  const el = document.createElement(node.type);

  // 하위 element를 render한 후 하위에 추가해 준다.
  // 재귀 함수를 호출하도록 하여 마지막 노드까지 랜더링
  node.children.map(renderElement).forEach((element) => {
    el.appendChild(element);
  });

  // 생성된 Element를 반환.
  return el;
}

function render(newVdom, container) {
  // vdom vs newVdom : diff algorithm
  // 실제로 React는 해당 포인트에서
  // 기존의 old Virtual DOM과 new Virtual DOM의 차이점을
  // 찾아서 변경된 부분만 실제 Real DOM에서 새롭게 rendering 한다.

  container.appendChild(renderElement(newVdom));
}
virtual DOM을 real DOM으로 랜더링 하는 함수입니다.

(github commit 바로가기)

랜더링 함수 (renderElement) 예외처리 추가

function renderElement(node) {
  // 해당 노드가 text 인 경우에 대한 예외 처리
  if (typeof node === "string") {
    return document.createTextNode(node);
  }
  // type에 해당하는 element를 생성.
  const el = document.createElement(node.type);

  // 하위 element를 render한 후 하위에 추가해 준다.
  // 재귀 함수를 호출하도록 하여 마지막 노드까지 랜더링
  node.children.map(renderElement).forEach((element) => {
    el.appendChild(element);
  });

  // 생성된 Element를 반환.
  return el;
}
virtual DOM의 최하단 node가 text 인 경우에는 TextNode를 만들도록 예외 처리를 추가하였습니다.

(github commit 바로가기)

랜더링 함수 (render) 사용

rendering 결과

render(<App />, document.getElementById("root"));
render 함수를 사용하여 랜더링 한 결과 입니다.

(github commit 바로가기)

이상으로 JavaScript로 간단하게 Virtual DOM을

rendering 하는 Easy React를 만들어 보았습니다.

(github 바로가기)

댓글