우아한 형제들 김민태님의 강의를 듣고 직접 정리한 콘텐츠 입니다.
가상돔을 만들기 위해 먼저 리액트의 jsx 문법을 파싱할 수 있는 babel환경을 구축해야 한다.
npm install @babel/cli @babel/core @babel/preset-react
package.json
{
"name": "tiny-react",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "babel src -d build -w",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"@babel/cli": "^7.12.8",
"@babel/core": "^7.12.9",
"@babel/preset-react": "^7.12.7"
}
}
scripts 명령어에 babel 빌드 명령어를 넣어 npm run build를 통해 파싱된 jsx의 결과물을 얻을 수 있다.
src/react.js
export function createElement(tagName, props, ...children) {
return {tagName, props, children}
}
src폴더에 react.js 파일을 만들고 바벨에서 사용하는 jsx 파싱 함수를 구현한다. createElement함수는 세번째 인자를 가변인수로 받는다. 왜냐하면 html 태그의 자식의 자식들이 계속 들어 올 수 있기 때문이다.
src/index.js
/* @jsx createElement */
import {createElement, render} from './react.js';
function Title (props) {
return (
<div>
<h2>바벨 트렌스 파일링 전</h2>
<h3>안녕하세요</h3>
</div>
)
}
render(<Title/>, document.querySelector('#root'));
src/index.js에 jsx로 간단한 리액트 컴포넌트를 만들어 본다.
build/index.js (npm run build->바벨 트렌스파일링 결과)
import { createElement, render } from './react.js';
function Title(props) {
return createElement("div", null,
createElement("h2", null, "\uBC14\uBCA8 \uD2B8\uB80C\uC2A4 \uD30C\uC77C\uB9C1 \uC804"),
createElement("h3", null, "\uC548\uB155\uD558\uC138\uC694"));
}
console.log(Title());
render(createElement(Title, null), document.querySelector('#root'));
npm run build를 하면 트렌스파일링 결과가 build폴더에 생긴다. 참고로 createElement의 첫번째 인자로 스트링이 넘어올수도 있고 함수가 넘어올수도 있다. 그 구분은 첫번째 인자가 jsx의 빌트인 컴포넌트인지 사용자가 만든 컴포넌트인지에 따라 달라지게 된다. 어떻게 바벨의 jsx 컴파일러가 같은 태그<> 형태임에도 사용자가 만든 컴포넌트와 빌트인 컴포넌트를 구별할 수 있을까? 리액트의 공식문서를 보면 사용자가 만든 컴포넌트는 대문자로 시작하라고 되어 있다. 결국 바벨의 jsx컴파일러는 대문자와 소문자로 시작하는 태그를 구별하여 스트링 혹은 함수자체로 createElement로 넘겨줄 수 있는 것이다. 여기서는 빌트인 html태그들이 넘어 왔기 때문에 스트링으로 들어온 것이다.
src/react.js (사용자 컴포넌트 구별 추가)
export function createElement(tagName, props, ...children) {
if (typeof tagName === 'function') {
return tagName.apply(null, [props, ...children])
}
return {tagName, props, children}
}
사용자가 만든 컴포넌트이면 대문자로 시작하고 함수로 넘어오기 때문에 createElement메서드에서 타입이 함수일 경우를 위와 같이 구분해준다. createElement함수로 props와 children이 가변인자로 들어가기 때문에 apply메서드를 통해 가변인자로 값들을 넣어준다.
출력결과
{tagName: "div", props: null, children: Array(2)}
children: Array(2)
0:
children: ["바벨 트렌스 파일링 전"]
props: null
tagName: "h2"
__proto__: Object
1:
children: Array(1)
0: "안녕하세요"
length: 1
__proto__: Array(0)
props: null
tagName: "h3"
__proto__: Object
length: 2
__proto__: Array(0)
props: null
tagName: "div"
__proto__: Object
'React.JS' 카테고리의 다른 글
hooks로 componentWillUnmount 구현하기 (0) | 2021.04.14 |
---|---|
react직접 만들어 보기(2) _ render 메서드 구현 (0) | 2021.01.02 |
redux-thunk 알아보기 (0) | 2019.11.24 |
DOM과 가상DOM 쉽게 이해해 보기 (1) | 2019.11.12 |
리액트 웹팩 기본 설정하기 (0) | 2019.10.24 |