이 글을 읽기에 앞서
이 게시글은 리액트처럼 동작 하는 코드를 작성해보는 것이지 리액트와 100% 동일한 코드를 작성하려 하는 것이 아닙니다.
이전게시글을 통해 JSX요소를 객체형태로 변환하는 것 까지 진행했다.
이제 JSX 컴포넌트는 tagName, props객체, children배열을 가진 객체로 관리된다.
그럼 이제 이걸 DOM api를 사용해서 객체를 DOM요소로 변환시키자.
makeDOM
/**
* @param {object} element createElement로 만들어진 요소
* @param {string} element.tagName 요소의 태그 이름
* @param {object} element.props 요소의 속성 객체
* @param {Array|undefined} element.children 요소의 자식 요소 배열
*/
export const makeDOM = (element) => {
if (typeof element === 'string' || typeof element === 'number') {
//element가 text거나 number인 경우 textNode로 만든다.
return document.createTextNode(element);
}
const DOMElement = document.createElement(element.tagName);
if (element.props)
//props를 실제 DOM요소에 적용시킨다.
Object.keys(element.props).forEach((key) => {
DOMElement[key] = element.props[key];
});
if (element.children) {
//children에 대해 재귀적으로 DOM요소를 만들어 현재 요소에 붙인다.
element.children.forEach((child) => {
DOMElement.appendChild(makeDOM(child));
});
}
return DOMElement; //최종 생성된 DOM요소를 반환한다.;
};
이렇게 하면 최종적으로 return 되는 DOMElement는 실제 DOM요소가 된다!
확인해보자
import App from './components/App';
import { makeDOM } from './core/makeDOM';
console.log(makeDOM(App()));
잘 변환된 것을 볼 수 있다.
그럼 이걸 DOM에 붙여주기만 하면 okay다.
render
렌더할 Element와 만들어진 DOM요소를 붙일 container를 인자로 받아서 container에 그려주자.
import { makeDOM } from './makeDOM';
/**
* @param {Object} content
* @param {HTMLElement} container
*/
export const render = (content, container) => {
const element = makeDOM(content);
container.appendChild(element);
};
그리고 html에 root요소를 붙이고, 이걸 index.js에서 render해주자.
index.html
<body>
<div id="root"></div>
</body>
index.js
import App from './components/App';
import React from './core/React';
const app = document.getElementById('root');
React.render(App(), app);
render결과
화면에 잘 그려진다!
리렌더링
자 이제 렌더링은 잘 됐다.
문제는 리렌더다.
어떻게 리렌더할까?
답은 간단하다. 그냥 새로운 컴포넌트로 갈아끼우면 된다.
Change컴포넌트를 하나 만들어보자.
import React from "../core/React";
export const Change = () => {
return <h1>바꼈지롱~</h1>;
};
이걸 3초있다가 리렌더시킨다.
import App from './components/App';
import { Change } from './components/Change';
import React from './core/React';
const app = document.getElementById('root');
React.render(App(), app);
setTimeout(() => {
app.innerHTML = '';
React.render(Change(), app);
}, 3000);
3초 이후에 내용이 바뀌는걸 확인할 수 있다.
현재의 리렌더 로직
1. app Element 내용 비운채로 렌더링
2. Change컴포넌트 element객체 생성
3. element에 대해서 DOM 요소 생성
4. app Element에 만들어진 DOM요소 추가
이게 매번 일어나면 굉장히 느릴 것이다.
특히 볼드체로 칠한 부분이 굉장히 비용이 높은 작업이므로 최적화가 필요하다.
다음 게시글에서 diffing을 통해 바뀐 부분만 리렌더 시켜보자.
https://github.com/d0422/make-react