React 컴포넌트의 생명주기(Lifecycle)에 대해 공부하려다가, 클래스형 컴포넌트의 개념이 확실하게 잡혀있지 않다는 걸 느껴서(잘 사용하지 않으니..😅) 먼저 React의 함수형 컴포넌트와 클래스형 컴포넌트에 대해 공부해보기로 했다.
: JavaScript 함수로 컴포넌트를 정의하는 방법
function FunctionComponent(props) {
return <h1>Hello, {props.name}</h1>
}
: ES6의 class 문법을 이용해 컴포넌트를 정의하는 방법
render()
메소드 안에서 React 엘리먼트를 리턴하는 형태this.props
로 props를 받을 수 있다.class ClassComponent extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
위의 두 컴포넌트는 React에게 동일한 컴포넌트이다.
const root = ReactDOM.createRoot(document.getElementById('root'));
function Clock(props) {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {props.date.toLocaleTimeString()}</h2>
</div>
);
}
function tick() {
root.render(<Clock date={new Date()} />);
}
setInterval(tick, 1000); // 1초마다 tick() 함수 실행
render()
라고 불리는 빈 메소드를 추가한다.render()
메소드 안으로 옮긴다.render()
내용 안에 있는 props를 this.props로 변경한다.const root = ReactDOM.createRoot(document.getElementById('root'));
class Clock extends React.Component { // 1. React.Component를 확장하는 ES6 class를 생성
render() { // 2. render() 메소드를 추가
return ( // 3. render() 메소드 안으로 함수의 내용을 옮긴다.
<div>
<h1>Hello, world!</h1>
<h2>It is {this.props.date.toLocaleTimeString()}</h2> // 4. props를 this.props로 변경한다.
</div>
);
}
}
function tick() {
root.render(<Clock date={new Date()} />);
}
setInterval(tick, 1000);
이렇게 함수로 정의했던 컴포넌트를 클래스로 바꾸어 정의할 수 있다.
지금은
useState()
훅을 이용해서 함수형 컴포넌트에 쉽게 state를 추가할 수 있지만, 예전 React에서는useState()
가 없었기 때문에 컴포넌트에 state를 추가하려면 이렇게 클래스형 컴포넌트로 작성해야만 상태를 추가할 수 있었다. 🙂
위에서는 외부에서 Clock 컴포넌트에 props로date
를 내려줬다.
이 date
를 Clock 컴포넌트 내부에서 관리하기 위해 state로 바꾸어보자.
render()
메소드 안에 있는 this.props.date
를 this.state.date
로 변경한다.this.state
를 지정하는 class constructor를 추가한다.const root = ReactDOM.createRoot(document.getElementById('root'));
class Clock extends React.Component {
// 2. class constructor를 추가해 초기 this.state를 지정해준다.
constructor(props) {
super(props);
this.state = {date: new Date()};
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}</h2> // 1. props를 state로 변경
</div>
);
}
}
root.render(<Clock />); // 3. 내려주던 props 삭제
여기까지 하면 위와 같은 결과를 볼 수 있다.
하지만 보시다시피 시간이 업데이트되지 않는 것을 확인할 수 있는데, 이는 우리가 tick()
함수와 setInterval()
함수를 없앴기 때문에 Clock 컴포넌트가 처음 렌더링된 상태에 멈춰있는 것이다.
이제 Clock 컴포넌트가 매초 스스로 시간을 업데이트할 수 있도록 메소드를 추가해보자.
이 또한 우리는 함수형 컴포넌트에서
setState()
를 이용해서 편하게 state를 업데이트하고 화면을 리렌더링할 수 있었지만.. 클래스형 컴포넌트에서는 생명주기 메소드(Lifecycle Methods)를 일일히 작성해줘야 한다..! 🙂
클래스형 컴포넌트에서 생명주기 메소드(Lifecycle Methods)를 선언하여 컴포넌트가 마운트되고 언마운트될 때 특정 코드를 실행하도록 할 수 있다.
componentDidMount()
: 컴포넌트가 마운트된 직후, 즉 트리에 삽입된 직후에 호출되는 메소드
componentDidMount() - React
componentWillUnmount()
: 컴포넌트가 마운트 해제되어 제거되기 직전에 호출되는 메소드
componentWillUnmount() - React
이제 코드에서 componentDidMount()
와 componentWillUnmount()
를 이용해 컴포넌트가 마운트될 때 타이머를 설정하고, 컴포넌트가 언마운트될 때 타이머를 해제해보자.
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
componentDidMount() {
this.timer = setInterval(() => {
this.tick();
}, 1000)
// timer와 같이 데이터 흐름 안에 포함되지 않는 어떤 항목을 보관할 필요가 있다면 자유롭게 클래스에 수동으로 부가적인 필드를 추가해도 된다.
}
componentWillUnmount() {
clearInterval(this.timer);
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}</h2>
</div>
);
}
}
마지막으로 Clock 컴포넌트에 tick()
메소드를 구현해보자.
컴포넌트의 로컬 state를 업데이트하기 위해서는 this.setState()
를 사용하면 된다.
const root = ReactDOM.createRoot(document.getElementById('root'));
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
componentDidMount() {
this.timer = setInterval(() => {
this.tick();
}, 1000)
}
componentWillUnmount() {
clearInterval(this.timer);
}
tick() {
this.setState({
date: new Date();
})
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}</h2>
</div>
);
}
}
root.render(<Clock />);
클래스컴포넌트 어려웠는데 깔끔하게 정리해주고 감사합니다 ㅎ 헷갈릴 때마다 참고하고 봐야겟어요 ! 함수형 컴포넌트가 있어서 얼마나 다행인지 모르겠어요
예전에 프로젝트 할 때, 구글링 시에 어떤건 클래스형, 어떤 건 함수형이어서 가져다 쓰고 싶어도 좀 어려움을 겪었던 기억이 있는데 한 번에 정리 된 걸 보니 그 때 이 글을 참고했더라면 편했겠다 생각이 드네요! ^_^ 둘 중에 하나만 쓰면 다른 하나는 잊어버리기 십상이라... 감사합니다 ㅎㅎ