React 함수형 컴포넌트와 클래스형 컴포넌트

지은·2023년 2월 20일
0

⚛️ React

목록 보기
15/23
post-custom-banner

React 컴포넌트의 생명주기(Lifecycle)에 대해 공부하려다가, 클래스형 컴포넌트의 개념이 확실하게 잡혀있지 않다는 걸 느껴서(잘 사용하지 않으니..😅) 먼저 React의 함수형 컴포넌트클래스형 컴포넌트에 대해 공부해보기로 했다.

Components와 Props - React

함수형 컴포넌트(Function Components)

: JavaScript 함수로 컴포넌트를 정의하는 방법

  • props 객체를 인자로 받고, React 엘리먼트를 리턴하는 형태
function FunctionComponent(props) {
  return <h1>Hello, {props.name}</h1>
}

클래스형 컴포넌트(Class Components)

: ES6의 class 문법을 이용해 컴포넌트를 정의하는 방법

  • React.Component를 확장하여 클래스를 만들고,
    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() 함수 실행


클래스형 컴포넌트

함수형 컴포넌트를 클래스형 컴포넌트로 바꾸는 법

  1. React.Component를 확장하여 ES6 class를 생성한다.
  2. render()라고 불리는 빈 메소드를 추가한다.
  3. 함수의 내용을 render() 메소드 안으로 옮긴다.
  4. render() 내용 안에 있는 props를 this.props로 변경한다.
  5. 남아있는 빈 함수 선언을 삭제한다.
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);

이렇게 함수로 정의했던 컴포넌트를 클래스로 바꾸어 정의할 수 있다.


클래스형 컴포넌트에 state 추가하기

지금은 useState() 훅을 이용해서 함수형 컴포넌트에 쉽게 state를 추가할 수 있지만, 예전 React에서는useState()가 없었기 때문에 컴포넌트에 state를 추가하려면 이렇게 클래스형 컴포넌트로 작성해야만 상태를 추가할 수 있었다. 🙂

State와 생명주기 - React

위에서는 외부에서 Clock 컴포넌트에 propsdate를 내려줬다.
date를 Clock 컴포넌트 내부에서 관리하기 위해 state로 바꾸어보자.

  1. render() 메소드 안에 있는 this.props.datethis.state.date로 변경한다.
  2. 초기 this.state를 지정하는 class constructor를 추가한다.
    이때, 클래스 컴포넌트는 항상 props로 기본 constructor를 호출해야 한다.
  3. Clock 컴포넌트에 내려주던 props는 삭제해도 된다.
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)를 선언하여 컴포넌트가 마운트되고 언마운트될 때 특정 코드를 실행하도록 할 수 있다.

  • 마운트(Mount): 컴포넌트가 처음 DOM에 렌더링되는 것
  • 언마운트(Unmount): 컴포넌트에 의해 생성된 DOM이 삭제되는 것

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 />);

profile
블로그 이전 -> https://janechun.tistory.com
post-custom-banner

6개의 댓글

comment-user-thumbnail
2023년 2월 21일

예전에 프로젝트 할 때, 구글링 시에 어떤건 클래스형, 어떤 건 함수형이어서 가져다 쓰고 싶어도 좀 어려움을 겪었던 기억이 있는데 한 번에 정리 된 걸 보니 그 때 이 글을 참고했더라면 편했겠다 생각이 드네요! ^_^ 둘 중에 하나만 쓰면 다른 하나는 잊어버리기 십상이라... 감사합니다 ㅎㅎ

답글 달기
comment-user-thumbnail
2023년 2월 21일

클래스형 컴포넌트는 잘 안쓰게 되던데 정말ㄹ.. 그러다보니 점점 까먹게 되는 그런 부분 같아요 ㅜ 저도 정리해서 클래스 개념을 다시 익혀야겠습니다!

답글 달기
comment-user-thumbnail
2023년 2월 22일

클래스컴포넌트 어려웠는데 깔끔하게 정리해주고 감사합니다 ㅎ 헷갈릴 때마다 참고하고 봐야겟어요 ! 함수형 컴포넌트가 있어서 얼마나 다행인지 모르겠어요

답글 달기
comment-user-thumbnail
2023년 2월 22일

클래스형은 너무 안 써서 볼 때마다 헷갈리는 것 같네욤 ㅜ 덕분에 다시 한번 더 잘 정리하고 갑니다 !!

답글 달기
comment-user-thumbnail
2023년 2월 23일

알면 좋은 클래스형.. 함수형이랑 같이 비교해서 보니 너무 이해 잘되고 좋네용 !!
하지만 너무 번거로운 ㅠㅠ

답글 달기
comment-user-thumbnail
2023년 2월 26일

와,, 라이프사이클 관련 코드도 직접 다 작성하고, render() 이런 것도 다 작성 해야하는군요. 함수형이 훨씬 편하긴 합니다. 근데 함수형에는 왜 저런 게 생략 가능한지 궁금해지긴 하네요

답글 달기