woolta

React - class컴포넌트와 function 컴포넌트의 차이점에 대해 알아보자.

wooltaUserImgb00032 | React | 2020-02-14

개요

훅이 도입되며 function component의 사용은 상태가 없는 컴포넌트에 주로 사용되었으나 훅이 나오며 function component 에도 상태가 추가되고 이제 새로 작성되는 컴포넌트의 작성을 대부분 class component 에서 function component 를 사용하게 되고 있습니다. 근데 과연 class 와 function 의 차이는 작성법 말고 무엇이 있을까요?

function component는 랜더되는 당시의 값으로 기억하고 사용한다.

차이점을 위한 컴포넌트 예시

우선 버튼을 클릭하면 2초 뒤에 부모로부터 받은 결제금액을 alert 으로 보여주는 컴포넌트를 class, function 컴포넌트로 각각 작성해 보도록 하겠습니다.

function component

function PaymentButtonF({pay}) {
  const payment = () => alert(`결제금액 : ${pay}`);

  const onPayClick = () => setTimeout(payment, 2000);

  return (
    <button onClick={onPayClick}>결제 (함수형 컴포넌트)</button>
  );
}
export default PaymentButtonF;

class component

class PaymentButtonC extends React.Component {

  payment = () => alert(`결제금액 : ${this.props.pay}`);
  onPayClick = () => setTimeout(payment, 2000);

  render() {
    return <button onClick={onPayClick}>결제 (클래스 컴포넌트)</button>;
  }
}
export default PaymentButtonC;

이제 각 payment 컴포넌트들을 자식으로 사용하고 pay를 전달하는 부모 컴포넌트를 작성해보도록 하겠습니다.

두가지를 선언하는 부모 컴포넌트

import React, {useState} from "react";
import PaymentButtonC from "./PaymentButtoonC";
import PaymentButtonF from "./PaymentButtonF";

function Payment() {
    const [pay, setPay] = useState(0);
    console.log(pay);
    return (
        <>
            <input value={pay} onChange={e => setPay(e.target.value)}/>
            <PaymentButtonC pay={pay}/>
            <PaymentButtonF pay={pay}/>
        </>
    );
}

export default Payment;

구동하는 방식은 동일한 것처럼 보이지만 위에서 말한 차이점을 생각해서 보시면 분명한 차이점이 존재합니다. 자 이제 두 코드의 실행결과를 확인해 보도록 하겠습니다.

function component 실행결과

https://image.woolta.com/functionComponentPay.gif

class component 실행결과

https://image.woolta.com/classComponentPay.gif

둘의 실행결과는 다음과 같습니다.

  • function component : 클릭시점의 pay 값을 2초 뒤에 노출
  • class component : 클릭시점이 아닌 2초뒤에 이벤트 발생시점의 pay를 노출

이와 같이 class component 로 작성 할 경우 내가 이벤트를 발생시켜도 딜레이가 발생하고 그사이에 이벤트의 필요한 값이 변경된다면 내가 의도하지 않은 결과가 나올 수 있습니다.

class component에서의 동작 방식

위의 두개의 예시를 다시 자세히 보면 클래스 컴포넌트는 this를 통해 값을 조회하는 것을 볼 수 있습니다.

payment = () => alert(`결제금액 : ${this.props.pay}`);
onPayClick = () => setTimeout(payment, 2000);

this 의 경우는 값이 변동되면 이에 따라 게속 변경됩니다. 때문에 이를 참조할때 이벤트가 최초 시작되는 것이 아닌 발생하는 시점에 this 에 있는 최신값을 가져오기때문에 의도하지 않은 결과가 나올 수 있게 됩니다.

해결방법

class component 에서 위와 같은 방법을 해결하기 위해선 다음과 같은 방식들로 해결 할 수 있습니다.

구조 분해 할당

payment = (pay) => alert(`결제금액 : ${pay}`);
onPayClick = () => {
    const {pay} = this.props;
    setTimeout(()=> this.payment(pay), 2000)
};

위와 같이 이벤트 선언전 this 에 대해 독립시켜 고정시키는 방식으로 선언한다면 이벤트를 클릭한 시점의 값으로 정보를 처리할 수 있습니다.

클로저 방식

class PaymentButtonC extends React.Component {

    render() {
        const props = this.props;
        const payment = () => alert(`결제금액 : ${props.pay}`);
        const onPayClick = () => setTimeout(payment , 2000);

        return <button onClick={onPayClick}>결제 (클래스 컴포넌트)</button>;
    }
}
export default PaymentButtonC;

클로저의 방식으로 아에 render 시점에 전부 props 를 가둬두었기 때문에 동일하게 동작하게 됩니다. 결국 이런 render 내부에서 함수를 정의하는 방식이 간결하게 표현하기 위해 결국 function 컴포넌트를 사용하게 됩니다.

참조

Copyright © 2018 woolta.com

gommpo111@gmail.com