1. 기존 함수형 컴포넌트를 클래스형 컴포넌트로 변경하기
이전에 만들어두었던 함수형 컴포넌트를 클래스형으로 수정한다.
기존 코드 :
/* @jsx createElement */
import { createElement, render } from './react';
function Title(props) {
return <h1>{ props.children }</h1>;
}
function Item(props) {
return <li style={`color:${props.color}`}>{props.children}</li>
}
const vdom = <p>
<Title label="React">React 정말 잘 만들기</Title>
<ul>
<Item color="red">첫 번째 아이템</Item>
<Item color="green">두 번째 아이템</Item>
<Item color="blue">세 번째 아이템</Item>
</ul>
</p>
render(vdom, document.querySelector('#root'));
vdom 변수를 App으로 변경하고, 아래 render 함수에서도 JSX 형태로 변경한다.
/* @jsx createElement */
import { createElement, render } from './react';
function Title(props) {
return <h1>{ props.children }</h1>;
}
function Item(props) {
return <li style={`color:${props.color}`}>{props.children}</li>
}
const App = <p> // 이 부분 변경
<Title label="React">React 정말 잘 만들기</Title>
<ul>
<Item color="red">첫 번째 아이템</Item>
<Item color="green">두 번째 아이템</Item>
<Item color="blue">세 번째 아이템</Item>
</ul>
</p>
render(<App />, document.querySelector('#root')); // 이 부분 변경
이제 좀 더 리액트스럽게 변경되었다.
이제 함수형을 클래스형으로 변경하자.
App.js
/* @jsx createElement */
import { createElement, render, Component } from './react';
class Title extends Component {
render() {
return <h1> { this.props.children } </h1>;
}
}
function Item(props) {
return <li style={`color:${props.color}`}>{props.children}</li>
}
const App = <p>
<Title label="React">React 클래스 컴포넌트 잘 만들기</Title>
<ul>
<Item color="red">첫 번째 아이템</Item>
<Item color="green">두 번째 아이템</Item>
<Item color="blue">세 번째 아이템</Item>
</ul>
</p>
render(<App />, document.querySelector('#root'));
react.js
export class Component {
constructor(props) {
this.props = props;
}
}
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;
}
function makeProps(props, children) {
return {
...props,
children: children.length === 1 ? children[0] : children,
};
}
export function createElement(tag, props, ...children) {
props = props || {};
if (typeof tag === 'function') {
if (tag.prototype instance of Component) {
const instance = new tag(makeProps(props, children));
return instance.render()
} else {
if (children.length > 0) {
return tag(makeProps(props, children))
} else {
return tag(props);
}
}
} else {
return { tag, props, children };
}
}
export function render(vdom, container) {
container.appendChild(createDOM(vdom));
}
현재는 앱이 변경된다면 (업데이트) render가 한 번만 되는 구조이다.
그런데 컴포넌트가 새로 생성되면 인스턴스가 계속 생겨서 함수형 컴포넌트와 같은 상태가 된다.
그래서 인스턴스 내에 상태를 저장할 수 있도록 만들기 위해서는
최초에만 인스턴스를 만들고, DOM에 실제로 마운트 된 이후에 안착되어서 render 된 이후에
컴포넌트가 삭제되고 다시 render될 때 '기존에 만들었던 인스턴스'를 재활용한 이후에 render만 호출할 것이다.
그래야 해당 컴포넌트 내부의 context가 계속 유지될 것이기 때문이다.
그 코드를 구현하려면 instance에 로직을 계속 처리해야 하기 때문에 지금까지 했던 것보다 훨씬 더 많이 작업을 해야 한다.
이 글은 클래스 컴포넌트의 기초적인 예시를 들어주기 위함이므로
실제의 현대 리액트를 따라가기 위해서는
인스턴스 관리뿐만 아니라 라이프 사이클(생애주기)도 구현해야 하기 때문에 지금은 무리가 있다.
언제 마운트 되고 언제 삭제되는지 흐름을 모두 React가 알아야 하기 때문에 이런 것들은 별도로 공부해서 알아보고,
이다음에는 함수형 컴포넌트에서 사용하는 Hook에 대해서 알아보자.
2. 참고할만한 글
1. 리액트의 컴포넌트
https://reactjs.org/docs/react-component.html
2. State와 Lifecycle in React
https://reactjs.org/docs/state-and-lifecycle.html
끝!