React Hook의 등장 배경

2025. 8. 22. 19:36프로젝트

0. 목차

  1. 초창기 React: 함수형 vs 클래스형
  2. 컴포넌트의 한계
  3. Hook의 등장

1. 초창기 React: 함수형 vs 클래스형

React가 처음 나왔을 때, 컴포넌트에는 두 가지 방식이 있었습니다.

 

함수형(Function) 컴포넌트

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

 

자바스크립트에서 함수가 호출되면, 그 실행 과정은 실행 컨텍스트(Execution Context) 라는 단위로 **스택(Stack)**에 쌓입니다. 실행이 끝나면 해당 컨텍스트는 스택에서 제거되고, 내부의 지역 변수와 매개변수도 함께 사라집니다.

즉, 함수형 컴포넌트가 렌더링될 때마다:

  1. 새로운 실행 컨텍스트가 스택에 생성되고,
  2. 함수 내부에서 선언된 변수들은 그 안에 저장되지만,
  3. 렌더링이 끝나면 실행 컨텍스트가 스택에서 제거되며 변수도 함께 소멸됩니다.

이 때문에 함수형 컴포넌트는 렌더링 사이에 상태값을 붙잡아 둘 수 없었고, 특정 시점(마운트, 업데이트, 언마운트)에 개입할 수 있는 방법도 존재하지 않았습니다.

 

 

클래스형(Class) 컴포넌트

import React from "react";

class Counter extends React.Component {
  constructor(props) {
    super(props);
    // 힙에 존재하는 인스턴스의 상태
    this.state = { count: 0 };
  }

  componentDidMount() {
    // 마운트 직후 (DOM 준비 후) 1회 실행: 예) 데이터 fetch, 구독 시작
    console.log("mounted");
  }

  componentDidUpdate(prevProps, prevState) {
    // 업데이트 직후 실행: 예) props 변화 대응
    if (prevState.count !== this.state.count) {
      console.log("count changed:", this.state.count);
    }
  }

  componentWillUnmount() {
    // 언마운트 직전 정리(clean-up)
    console.log("unmounted");
  }

  handleInc = () => this.setState(s => ({ count: s.count + 1 }));

  render() {
    return (
      <button onClick={this.handleInc}>
        Count: {this.state.count}
      </button>
    );
  }
}

 

반대로 클래스형 컴포넌트(Class Component)는 React가 new 키워드로 인스턴스를 생성하여 힙(Heap) 메모리에 보관합니다.

  • 이 인스턴스는 컴포넌트가 언마운트될 때까지 메모리에 남아 있으며,
  • this.state와 라이프사이클 메서드(componentDidMount, componentDidUpdate, componentWillUnmount)는 그 인스턴스 내부에 저장되어 렌더링 사이에도 계속 유지됩니다.

즉, 클래스형 컴포넌트는 한 번 생성된 객체가 메모리에 살아남아 있기 때문에 상태 관리와 생명주기 제어가 가능했던 것입니다.


2. Class 컴포넌트의 한계

하지만 클래스 방식은 점점 문제가 드러났습니다.

  1. 복잡한 라이프사이클 로직
    • 데이터 fetch → 구독(subscribe) → 정리(clean-up) 같은 로직이 componentDidMount, componentDidUpdate, componentWillUnmount로 흩어져 관리됐습니다.
    • 한 기능에 관련된 코드가 여러 메서드에 나뉘다 보니 유지보수가 어려웠습니다.
  2. 로직 재사용의 불편함
    • 여러 컴포넌트에서 동일한 상태 로직을 쓰려면 HOC(Higher-Order Component)나 Render Props 같은 패턴을 사용해야 했습니다.
    • 이 방식은 코드가 중첩되고 가독성이 떨어졌습니다.
  3. this 바인딩 문제
    • 클래스 내부 메서드에서 this를 올바르게 쓰기 위해 constructor에서 바인딩하거나, 화살표 함수를 쓰는 등의 번거로움이 있었습니다.
  4. 러닝 커브
    • 함수형은 단순한데, 클래스 문법은 초심자에게 어렵게 느껴졌습니다.
    • 특히 자바스크립트의 this 동작 원리를 알아야 했습니다.

3. Hook의 등장

React 팀은 “클래스 없이도 상태와 라이프사이클을 다룰 수 있게 만들자”라는 목표로 Hook을 도입했습니다. (React v16.8, 2019년)

  • useState: 함수형 컴포넌트에서도 상태를 가질 수 있게 함
  • useEffect: 라이프사이클을 하나의 API로 단순화 (mount/update/unmount 모두 처리)
  • useContext, useReducer, useMemo, useCallback: 다양한 상태/성능 최적화 도구 제공

Hook의 핵심 원리는 React가 함수 호출 외부(Heap)에 상태 저장소를 두고, 호출 순서를 기반으로 상태를 이어주는 것입니다.
덕분에 함수형 컴포넌트도 “상태를 가진 UI 단위”로 진화할 수 있었습니다.

 


4. 마무리

이번 글에서는 React Hook의 등장배경과 전반적인 개요를 다뤘습니다.
각 Hook의 자세한 내용 및 사용법은 앞으로 개별 포스팅에서 더 깊이 살펴보겠습니다.