이 글의 목적은 바닐라 JavaScript (TypeScript)를 사용하여 React의 클래스 컴포넌트를 구현함으로써, React의 장점과 효율성을 깊이 있게 이해하는 것이다. 컴포넌트 기반 UI 구성과 생명주기 관리, 상태 관리를 직접 구현해 보겠다.
리액트 클래스 컴포넌트는 ES6 클래스 문법을 사용하여 정의되며, 리액트의 주요 기능인 상태 관리와 생명주기 메서드를 활용할 수 있다.
주요 생명주기 메서드
componentWillMount: 컴포넌트가 마운트되기 전 호출된다.componentDidMount: 컴포넌트가 마운트된 후 호출된다.componentWillUpdate: 컴포넌트가 업데이트되기 전 호출된다.componentDidUpdate: 컴포넌트가 업데이트된 후 호출된다.componentWillUnmount: 컴포넌트가 언마운트 되기 전에 호출된다.
먼저, ComponentProps와 ComponentState 인터페이스를 정의하여 컴포넌트의 속성과 상태를 타입으로 명시했다.
export interface ComponentProps {
[key: string]: any;
}
export interface ComponentState {
[key: string]: any;
}
그 다음, Component 클래스를 정의했다. 이 클래스는 props와 state를 초기화하고 생명주기 메서드를 호출한다.
export class Component {
props: ComponentProps;
state: ComponentState;
constructor(props: ComponentProps) {
this.props = props;
this.state = {};
this.componentWillMount();
this.render();
this.componentDidMount();
}
setState 메서드는 새로운 상태 객체를 기존 상태 객체와 병합하고, 컴포넌트가 업데이트되기 전과 후에 각각 componentWillUpdate와 componentDidUpdate 메서드를 호출한다. 그런 다음, 컴포넌트의 UI를 다시 렌더링한다.
setState(newState: ComponentState) {
this.componentWillUpdate();
for (let key in newState) {
if (newState.hasOwnProperty(key)) {
this.state[key] = newState[key];
}
}
this.render();
this.componentDidUpdate();
}
컴포넌트가 마운트 및 업데이트될 때 호출되는 생명주기 메서드를 정의했다.
componentWillMount() {
// 컴포넌트가 마운트 되기 전 호출
}
componentDidMount() {
// 컴포넌트가 마운트 된 후 호출
}
componentWillUpdate() {
// 컴포넌트가 업데이트 되기 전 호출
}
componentDidUpdate() {
// 컴포넌트가 업데이트 된 후 호출
}
componentWillUnmount() {
// 컴포넌트가 언마운트 되기 전에 호출
// 여기에 리소스 해제 로직 추가
}
render 메서드는 컴포넌트의 UI를 렌더링한다.
render() {
// UI 렌더링 함수
}
}
MainPage 컴포넌트를 Component 클래스를 상속받아 구현했다. 이 컴포넌트는 state를 초기화하고, 생명주기 메서드를 오버라이드하여 로그를 출력한다.
import { Component, ComponentProps } from '../Component';
export default class MainPage extends Component {
constructor(props: ComponentProps) {
super(props);
this.state = { count: 0 };
}
componentWillMount() {
console.log('MainPage will mount');
}
componentDidMount() {
console.log('MainPage did mount');
}
componentWillUpdate() {
console.log('MainPage will update');
}
componentDidUpdate() {
console.log('MainPage did update');
}
render() {
const element = document.getElementById('root');
if (element) {
element.innerHTML = `
<div>
<p>Count: ${this.state.count}</p>
<button id="increment">Click me!</button>
</div>
`;
document.getElementById('increment')?.addEventListener('click', () => {
this.setState({ count: this.state.count + 1 });
});
}
}
}
