Miracle Morning, LHWN

23. 클래스형 컴포넌트 본문

IT 기술/[React] 기본

23. 클래스형 컴포넌트

Lee Hye Won 2021. 5. 31. 16:44

# 최근에는 클래스형 컴포넌트를 잘 사용하지 않는 추세이지만, 예전에 만들어진 리액트 관련 라이브러리는 Hooks 지원이 안되는 경우도 있고 react-native 관련 라우터 라이브러리 react-native-navigation 의 경우에도 클래스형 컴포넌트를 써야하는 경우가 있다.

따라서 클래스형 컴포넌트도 알고 있으면 도움은 된다.

우선, 함수형 컴포넌트 예시를 보자.

import React from 'react';

function Hello({ color, name, isSpecial }) {
  return (
    <div style={{ color }}>
      {isSpecial && <b>*</b>}
      안녕하세요 {name}
    </div>
  );
}

Hello.defaultProps = {
  name: '이름없음'
};

export default Hello;

이를 클래스형 컴포넌트로 변환해보면 아래와 같다.

import React, { Component } from 'react';

class Hello extends Component {
   /* defaultProps 설정하는 또 다른 방법
    static defaultProps = {
      name: '이름없음'
    };
   */
    render() {
    const { color, name, isSpecial } = this.props;
    return (
      <div style={{ color }}>
        {isSpecial && <b>*</b>}
        안녕하세요 {name}
      </div>
    );
  }
}

Hello.defaultProps = {
  name: '이름없음'
};

export default Hello;

# 클래스형 컴포넌트에는 render() 함수가 반드시 있어야 한다.

# render() 함수에서 렌더링하고 싶은 JSX 를 return 해주면 된다.

# props 를 조회해야 할 때에는 this.props 를 조회하면 된다.

전에 작성했었던 Counter 도 클래스형 컴포넌트로 변경해보자.

import React, { useReducer } from 'react';

function reducer(state, action) {
  switch (action.type) {
    case 'INCREMENT':
      return state + 1;
    case 'DECREMENT':
      return state - 1;
    default:
      return state;
  }
}

function Counter() {
  const [number, dispatch] = useReducer(reducer, 0);

  const onIncrease = () => {
    dispatch({ type: 'INCREMENT' });
  };

  const onDecrease = () => {
    dispatch({ type: 'DECREMENT' });
  };

  return (
    <div>
      <h1>{number}</h1>
      <button onClick={onIncrease}>+1</button>
      <button onClick={onDecrease}>-1</button>
    </div>
  );
}

export default Counter;

아래는 클래스형 컴포넌트이다.

import React, { Component } from 'react';

class Counter extends Component {
  handleIncrease() {
    console.log('increase');
  }

  handleDecrease() {
    console.log('decrease');
  }

  render() {
    return (
      <div>
        <h1>0</h1>
        <button onClick={this.handleIncrease}>+1</button>
        <button onClick={this.handleDecrease}>-1</button>
      </div>
    );
  }
}

export default Counter;

onClick 함수를 작성할 때 render() 안에 함수를 구현할 수는 있지만, 일반적으로는 클래스 안에 커스텀 메서드를 선언한다.

클래스 내부에 종속된 함수'메서드'라고 부르며, 클래스에서 커스텀 메서드를 만들 때에는 보통 이름을 handle... 으로 짓는다.

<button onClick={this.handleIncrease}>+1</button>

여기서 this 는 컴포넌트 인스턴스를 가리킨다.

handleIncrease() 함수 안에서 this 값을 조회해보면 undefined 가 나오는데, 이 이유는 handleIncrease, handleDecrease 메서드들을 각 button 의 이벤트로 등록하는 과정에서 '메서드 (handleIncrease) <> 컴포넌트 인스턴스 (this)' 관계가 끊겨버린다.

이를 해결하기 위한 방법은 아래 3가지가 있다.

(1) 클래스의 생성자 메서드 constructor 에서 bind 작업을 해주는 것이다.

(2) 커스텀 메서드를 선언할 때 화살표 함수 문법을 사용해서 작성하는 것이다.

(3) onClick 에서 새로운 함수를 만들어서 전달하는 것이다. (비추천)

하나씩 보자.

(1) 클래스의 생성자 메서드 constructor 에서 bind 작업을 해주는 것이다.

import React, { Component } from 'react';

class Counter extends Component {
  constructor(props) {
    
    super(props); // 이 클래스가 컴포넌트로서 작동할 수 있도록 해주는 컴포넌트 쪽에 구현되어 있는 생성자 함수를 먼저 실행해주고, 
                  // 우리가 할 작업을 하겠다는 의미
    // bind 함수를 사용하면 해당 함수에서 가르킬 this 를 직접 설정해줄 수 있다.
    this.handleIncrease = this.handleIncrease.bind(this); 
    this.handleDecrease = this.handleDecrease.bind(this);
  }

  handleIncrease() {
    console.log('increase');
    console.log(this);
  }

  handleDecrease() {
    console.log('decrease');
  }

  render() {
    return (
      <div>
        <h1>0</h1>
        <button onClick={this.handleIncrease}>+1</button>
        <button onClick={this.handleDecrease}>-1</button>
      </div>
    );
  }
}

export default Counter;

(2) 커스텀 메서드를 선언할 때 화살표 함수 문법을 사용해서 작성하는 것이다.

class-properties 라는 문법을 사용해서 클래스형 컴포넌트에서 화살표 함수를 사용해서 메서드를 구현한다.

class-properties 문법은 클래스에 특정 속성을 선언할 수 있게 해주는 문법이다.

아직 정식 자바 스크립트 문법이 아니지만 CRA(Create-React-App) 로 만든 프로젝트에는 적용 되어있는 문법이기 때문에 바로 사용할 수 있다.

보통 CRA 로 만든 프로젝트에서 커스텀 메서드를 만들 때 이 방법을 사용한다.

import React, { Component } from 'react';

class Counter extends Component {
  handleIncrease = () => {
    console.log('increase');
    console.log(this);
  };

  handleDecrease = () => {
    console.log('decrease');
  };

  render() {
    return (
      <div>
        <h1>0</h1>
        <button onClick={this.handleIncrease}>+1</button>
        <button onClick={this.handleDecrease}>-1</button>
      </div>
    );
  }
}

export default Counter;

(3) onClick 에서 새로운 함수를 만들어서 전달하는 것이다. (비추천)

이 방법은 렌더링 할 때 마다 함수가 새로 만들어지기 때문에 컴포넌트 최적화 시에 매우 까다롭다.

return (
  <div>
    <h1>0</h1>
    <button onClick={() => this.handleIncrease()}>+1</button>
    <button onClick={() => this.handleDecrease()}>-1</button>
  </div>
);

 

클래스형 컴포넌트에서 상태 관리해보기

state 라는 것을 사용하는데 constructor 내부에서 this.state 를 설정해주면 된다.

클래스형 컴포넌트에서 state 는 무조건 객체 형태여야 하며, render 메서드에서 state 를 조회하려면 this.state 로 사용하면 된다.

import React, { Component } from 'react';

class Counter extends Component {
  constructor(props) {
    super(props);
    this.state = {
      counter: 0
    };
  }
  handleIncrease = () => {
    console.log('increase');
    console.log(this);
  };

  handleDecrease = () => {
    console.log('decrease');
  };

  render() {
    return (
      <div>
        <h1>{this.state.counter}</h1>
        <button onClick={this.handleIncrease}>+1</button>
        <button onClick={this.handleDecrease}>-1</button>
      </div>
    );
  }
}

export default Counter;

근데 우리가 화살표 함수 문법을 사용해서 메서드를 작성할 수 있게 해줬던 class-properties 를 사용하면

굳이 constructor 를 작성하지 않고도 할 수 있다. (CRA 로 만든 프로젝트에서는 이 방법을 가장 많이 사용한다.)

import React, { Component } from 'react';

class Counter extends Component {
  state = {
    counter: 0
  };
  handleIncrease = () => {
    console.log('increase');
    console.log(this);
  };

  handleDecrease = () => {
    console.log('decrease');
  };

  render() {
    return (
      <div>
        <h1>{this.state.counter}</h1>
        <button onClick={this.handleIncrease}>+1</button>
        <button onClick={this.handleDecrease}>-1</button>
      </div>
    );
  }
}

export default Counter;

 

상태 업데이트 해보기

상태를 업데이트 할 때는 this.setState 함수를 사용해서 객체 안에 업데이트 하고 싶은 값을 넣어서 호출해주면 된다.

import React, { Component } from 'react';

class Counter extends Component {
  state = {
    counter: 0
  };
  handleIncrease = () => {
    this.setState({
      counter: this.state.counter + 1
    });
  };

  handleDecrease = () => {
    this.setState({
      counter: this.state.counter - 1
    });
  };
}

export default Counter;

이전에 학습했던 useState 에서 함수형 업데이트를 했던 것 처럼 클래스형 컴포넌트에서도 setState 를 사용해서 함수형 업데이트를 할 수 있다.

  handleIncrease = () => {
    this.setState(state => ({
      counter: state.counter + 1
    }));
  };

  handleDecrease = () => {
    this.setState(state => ({
      counter: state.counter - 1
    }));
  };

더 자세한 내용은 아래 출처에


출처 : https://react.vlpt.us/basic/24-class-component.html

 

24. 클래스형 컴포넌트 · GitBook

24. 클래스형 컴포넌트 이제는 잘 사용하지 않지만, 그래도 클래스형 컴포넌트에 대해서 알아봅시다! 앞으로 이 강의에서 클래스형 컴포넌트를 사용하는 일은 거의 없겠지만 그래도 알아둘 필요

react.vlpt.us

 

Comments