[React] Class Component vs Function Component

Mandy·2023년 9월 18일
0
post-thumbnail

클래스형 컴포넌트

import { Component } from 'react';

class Greeting extends Component {
  render() {
    return <h1>Hello, {this.props.name}!</h1>;
  }
}

함수형 컴포넌트

export default function Greeting() {
  return (
    <h1>Hello, world!</h1>;
    )

}

리액트를 공부하다 보면
위의 두가지 형태의 컴포넌트를 발견할 수 있다.
최근에 리액트를 배우기 시작한 사람들은 아마 대부분 후자 컴포넌트인 함수형 컴포넌트를 주로 사용하고 있을 것이다.

하지만 아직까지 클래스형 컴포넌트를 사용하는 회사나 팀도 있다고 하니 클래스형 컴포넌트가 무엇이고, 함수형 컴포넌트와는 어떤 차이가 있는지 알면 좋을 것이다.

그리고 왜 이제는 대다수가 함수형 컴포넌트만을 사용하려는지까지 알게된다면 더욱 개발에 도움이 될 것 이다.




클래스형 컴포넌트란?

Component is the base class for the React components defined as JavaScript classes.
(클래스형)컴포넌트는 자바스크립트 클래스로 정의된 React 컴포넌트의 베이스 클래스입니다.
-리액트 공식문서(react.dev)

클래스형 컴포넌트는 말그대로 클래스로 만든 컴포넌트이다.

클래스형 컴포넌트의 주요 특징에 대해 알아보자.

render()

class Clock extends React.Component {
  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

클래스형 컴포넌트는 반드시 render() 메서드가 존재해야만 하고 이 메서드를 통해 jsx가 렌더링된다.
그렇지만 함수형 컴포넌트에서는 return 문 안에 jsx를 포함하기만 하면 된다.



constructor()

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }

  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

this.state에 객체를 할당해서 지역 state를 초기화 하거나 인스턴스에 이벤트 처리를 바인딩 할때에 사용되며 이러한 목적이 없는 경우에는 구현하지 않아도 된다.

그리고 contructor() 내부에서 state를 업데이트하는 setState() 를 호출해서는 안된다.

대신에 constructor()setState() 없이도 this.state 를 직접 할당해서 사용할 수 있는 유일한 영역이다.

또한, constructor() 내부에서 어떤 다른 사이드 이펙트나 구독 작업을 수행하게 해서는 안된다는 점에 유의하자.

그리고 constructor() 에서 this.state를 직접 할당할 수 있다고 해서 props를 할당하는 행위를 해서는 안된다.

props 값이 변해도 state에 반영되지 않는 문제가 생길 수 있기 때문이므로 props를 어디선가 사용하고 싶다면 그냥 this.props로 사용하길 권장한다.



Life Cycle

컴포넌트에는 라이프 사이클이 있다.

이것은 클래스형 컴포넌트와 함수형 컴포넌트 모두 해당되는 사항이다.

라이프 사이클이 무엇인지 간단하게 설명하자면 컴포넌트가 마운트(화면에 렌더링)되고 언마운트(마운트 해제)될 때까지의 주기를 말한다.

예컨대, 컴포넌트가 마운트되는 순간 콘솔로그를 출력하고 싶다.

라고 할 때 특정 메서드나 useHooks을 통해 제어할 수 있는 것이다.

그리고 클래스형 컴포넌트에서 라이프 사이클을 컨트롤 할 수 있는 방법은 직접 메서드를 이용하는 것이다.

클래스형 컴포넌트에는 라이프 사이클과 관련된 메서드가 굉장히 많지만, 현재는 일반적으로 사용되는 메서드는 3개 정도이다.

라이프 사이클과 메서드를 다이어그램으로 보고싶다면 아래 링크에 접속해보아도 좋다.

컴포넌트 라이프사이클과 메서드
출처: 리액트 공식문서

componentDidMount():

컴포넌트가 마운트된 직후에 호출된다.

즉, dom 트리에 삽입이 된 직후 호출되며 서버와의 데이터 통신을 수행하기에 적합한 위치이다.

그러나 여기서 setState() 를 호출해서 상태를 변화시키는 것은 권장하지 않는다.

이것은 함수형 컴포넌트에서도 useEffect 훅 내에서 가급적이면 상태변화를 일으키지 않아야 한다는 것과 비슷한 맥락이다.

componentDidUpdate() :

컴포넌트가 업데이트된 직후에 호출된다.

즉, 이 메서드는 최초 렌더링에서는 호출되지 않는다.

컴포넌트가 업데이트 되었을 때 dom 조작을 위해 사용하면 좋은 메서드이며, 이전과 현재 props를 비교하는 조건문에 데이터 요청 함수를 작성할 수도 있다.

여기서 주의할 점은 이 메서드에서도 setState()를 호출해서 상태를 변화시킬수는 있지만 조건문으로 감싸져있지 않으면 무한 반복과 컴포넌트 성능 저하를 일으킬 수 있다.

componentWillUnmont() :

컴포넌트가 마운트 해제되어 dom트리에서 제거되기 "직전"에 호출된다.

제거된 이후에 호출되는게 아님을 명심하자.

이 메서드에서는 보통 클린업 함수라고도 불리는 타이머 제거, 네트워크 요청 취소 및 연결 해제, 구독 해제 등을 수행하면 좋다.

이 메서드가 수행되고나면 컴포넌트가 다시 렌더링되지 않으므로 setState()를 호출해서는 안된다.

컴포넌트 인스턴스가 마운트 해제되면 영상을 되감기 하듯이, 연어가 강을 거슬러 올라가듯이 되지 않는다. 즉, 절대로 다시 마운트 되지 않는다.

.bind(this)
클래스형 컴포넌트에서는 자동으로 인스턴스에 바인딩 되지않기 때문에 직접 .bind를 이용해서 바인딩했었다.

그렇지만 es6에서 화살표 함수가 도입되면서부터 .bind를 사용하지 않아도 바인딩이 가능해졌다.




함수형 컴포넌트란?

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

함수형 컴포넌트란 이름의 첫 글자가 대문자로 시작하는 JavaScript 함수 형태로 선언된 컴포넌트이다.

본래 함수형 컴포넌트는 hooks의 도입 이전에는 상태관리를 할 수 없었으나, React 16.8 hooks의 도입 이후 부터는 상태관리가 가능해졌다.

특징은 다음과 같다.



useHooks의 도입

React 16.8이후 useHooks의 도입으로 함수형 컴포넌트와 클래스형 컴포넌트의 위상은 역전하게 되었다.

특히, 이러한 결과의 원인이 된 대표적인 hooks는 useStateuseEffect이다.

useState의 도입으로 함수형 컴포넌트 내에서도 상태관리가 가능해졌다.

import {useState} from react;

const [changeColors, setChangeColors] = useState(false)

위와 같이 useState라는 훅을 사용하여 구조분해할당한 배열의 첫번째 요소가 관리할 상태가 되며 두번째 요소가 클래스형 컴포넌트에서의 setState() 즉, 상태를 업데이트하는 역할을 하는 함수이다.

import {useEffect} from react;

useEffect(() => {
/** 수행할 코드를 작성한다.*/
  console.log("welcome!");
} , [])

useEffect 훅은 기존에 여러 메서드들로 관리하던 라이프 사이클 제어를 담당한다. useEffect 훅의 첫번째 인자에는 수행할 콜백 함수가 작성되어야 하고 두번째 인자에는 의존성 배열 목록이 작성되어야 한다.

두번째 인자에 빈 배열이 들어가면 componentDidMount() 와 유사하게 컴포넌트가 마운트 된 직후에만 첫번째 인자인 콜백함수가 동작하게 된다.

useEffect 내에서 return 문 이후에 작성되는 구문은 componentWillUnmont() 메서드와 유사하게 클린업 함수를 컴포넌트 마운트가 해제될 때 수행한다.




왜 함수형 컴포넌트를 사용해야 하는가?

1. 재사용성과 가독성이 높다
함수형 컴포넌트는 기본적으로 자바스크립트 함수의 형태를 하고 있기 때문에, export 하고 import 하기 쉽다.

그렇기에 다른 컴포넌트에서 재사용하기 좋은 형태의 컴포넌트인 것이다.

함수의 형태를 하고 있기에 다른 컴포넌트 로직에 더욱 쉽게 조합할 수 있다는 장점도 있다.

또한 클래스형 컴포넌트보다 복잡하지 않은 단순한 구조를 갖추고 있어 코드를 쉽게 읽을 수 있고, 유지보수하기도 수월하다.

그리고 앞에서 설명했듯이 클래스형 컴포넌트는 라이프 사이클 관리를 위해서 메소드를 사용해야 하며, render() 메서드와 this 의 사용이 필수적이기에 가독성 측면에서 불리하다.

Class components are still supported by React, but we don’t recommend using them in new code.

클래스형 컴포넌트는 여전히 React에서 지원되지만 새 코드에서 사용하지 않는 것이 좋습니다.

2. 리액트에서 공식적으로 권장함

현재 리액트의 공식문서에서도 클래스형 컴포넌트보다 함수형 컴포넌트로 작성하는 것을 권장하고 있기 때문에 더욱 함수형 컴포넌트를 사용해야 한다.


마무리

React 16.8 이후에 웹 프론트엔드 개발을 시작한 사람이라 당연하게 함수형 컴포넌트를 사용하고 있었지만, 이제는 클래스형 컴포넌트와 함수형 컴포넌트의 차이에 대해서 알게 되었다.

이렇게 정리된 글을 읽는 것도 좋지만, 리액트에서 작성한 공식 문서를 정독 하는것이 중요하다고 생각한다.

-끝




출처
https://legacy.reactjs.org/docs/react-component.html
https://react.dev/reference/react/Component

profile
즐코 행코 하세용

0개의 댓글