Group Study (2020-2021)/ReactJS + Spring Boot ToyProject

[웹 3팀] 2. Delete 기능을 구현해보면서 고민한 지점(Class Component vs Functional Component + Hook)

dolphinSarah 2020. 12. 27. 00:44

Delete 기능을 처음 구현하려고 했을 때는 Detail 페이지를 만들기 전이어서 아래와 같이 삭제 버튼을 만들어주었다. 

detail page 만들기 전의 delete 기능 구현 화면

다른 분들의 작업을 이어서 구현하게 되었는데, pull부터 받고 했어야 하는데 업데이트 사항이 없다고 착각하고 구현을 시작했다. 처음에는 Class Component로 작성되어 있었고, 나에게도 Class Component가 익숙했기 때문에 그렇게 작성을 하고 merge를 시도했는데, pull을 받으라는 메시지가 떴다. 

pull을 받고 나니, 여기저기서 conflict가 발생했지만 가장 큰 차이점은 코드가 Functional Component와 Hook을 사용하여 작성되어 있었다. 그렇다면 형태를 하나로 통일을 해야하는데, 어떤 차이가 있는지, 어떤 형태로 통일할지 잘 모르겠어서 찾아보게 되었다. 

찾아보니 많은 개발자들이 Class Component보다 Functional Component를 선호한다는 것을 알 수 있었다. (Hook이라는 개념이 등장하면서부터..!) 또, 공식 문서에서도 Functional Component와 Hook을 함께 사용할 것을 권장하고 있다. 

먼저 Component의 기능을 한 번 짚어보면, Component는 데이터가 주어졌을 때 이에 맞추어 UI를 만들어주는 기능을 하는 것은 물론, Life Cycle API를 통해 Component가 화면에 나타날 때, 사라질 때, 변할 때 작업들을 수행할 수도 있다.

Class Component와 Functional Component의 역할은 동일하다. 차이점이 있다면, Class Component의 경우 state 기능 및 Life Cycle 기능을 사용할 수 있고, 임의의 메서드를 정의할 수 있다는 점이다. render 함수가 꼭 있어야 하고, 그 안에는 보여줘야 할 JSX를 반환해야 한다.

Functional Component는 Class Component보다 선언하기 편하고, 메모리 자원을 덜 사용한다는 장점이 있다. 과거에는 Functional Component에서 state와 Life Cycle API를 사용할 수 없다는 단점이 있었는데, 이런 단점은 앞서 언급했듯이 Hook이 도입되면서 해결되었다.

아래의 코드를 보면서, state에 대해 알아보자.

import React, { Component } from 'react';

class Counter extends Component {
  constructor(props) {
    super(props);
    this.state = {
      number: 0
    };
  }
  render() {
    const { number } = this.state; // state 를 조회할 때에는 this.state 로 조회합니다.
    return (
      <div>
        <h1>{number}</h1>
        <button
          // onClick 을 통하여 버튼이 클릭됐을 때 호출 할 함수를 지정합니다.
          onClick={() => {
            // this.setState를 사용하여 state에 새로운 값을 넣을 수 있습니다.
            this.setState({ number: number + 1 });
          }}
        >
          +1
        </button>
      </div>
    );
  }
}

export default Counter;

state는 Component 내부에서 바뀔 수 있는 값을 의미한다. props의 경우 부모 Component가 설정해서 자식 Component는 읽기만 할 수 있고, 값을 바꾸기 위해서는 부모 Component에서 직접 변경을 해야 한다. 자식 Component 내에서 값을 변화해야 하는 경우 state를 사용한다.

Class Component에서는 class 내의 constructor 메서드에서 state의 초기값을 생성해줘야 한다. 그리고 constructor를 작성할 때 super(props)를 반드시 호출해야 한다. state를 조회할 때는 this.state로 조회하며, state의 값을 변경하고 싶을 때this.setState 함수를 통해서 바꾸어준다

Class Component는 Stateful Component, Functional Component는 Stateless Component라고 한다.  Class Component는 로직과 상태를 Component 내에서 구현하기 때문에 stateful로 불리고, 상대적으로 복잡한 UI 로직을 갖고 있다. 반면, Functional Component는 state를 사용하지 않고 단순하게 데이터를 받아서(props) UI에 뿌려주기 때문에 stateless라고 불린다. 

숫자를 state로 선언하고, 클릭하면 숫자를 1 증가시키는 버튼과 감소시키는 버튼을 Class Component와 Functional Component + Hook으로 작성한 예다. 

// Class Component 
import React from "react";

class App extends React.Component {
  state = {
      number: 0
  };
  render() {
    return (
      <div style={{ "textAlign": "center" }}>
        <div style={{ "fontSize": "100px" }}>{this.state.number}</div>
        <button onClick={this.handleClickIncrement}>더하기</button>
        <button onClick={this.handleClickDecrement}>빼기</button>
      </div>
    );
  }
  handleClickIncrement = () => {
    this.setState(state => ({
      number: state.number + 1
    }));
  };
  handleClickDecrement = () => {
    this.setState(state => ({
      number: state.number - 1
    }));
  };
}

export default App;

// Functional Component + Hook
import React, { useState } from "react";

const App = () => {
  const [number, setNumber] = useState(0);
  return (
    <div style={{ textAlign: "center" }}>
      <div style={{ fontSize: "100px" }}>{number}</div>
      <button onClick={() => setNumber(number + 1)}>더하기</button>
      <button onClick={() => setNumber(number - 1)}>빼기</button>
    </div>
  );
};

export default App;

Class Component에서는 setState를 사용하여 state를 변경할 때, 항상 새로운 객체를 전달해줘야하는 불편함이 있는데, useState를 사용하여 얻은 함수 setNumber에서는 원하는 값을 인자로 전달하기만 하면 된다. 

이런 식으로 Hook들을 필요한 곳에 사용하면서 Logic의 재사용이 가능하다는 점이 Functional Component + Hook의 가장 큰 장점이다. 

이렇게 React Hook이 등장하면서 Functional Component를 더 많이 사용하는 추세가 되었지만, 오래된 React의 코드의 경우 Class Component로 이루어진 경우가 더 많으므로 두 가지 모두 잘 알고 있어야 React로 개발할 때 어려움을 겪지 않을 것 같다.