프로그래밍/ReactJS

React 컴포넌트 마스터하기: 함수형과 클래스형, 그리고 훅의 모든 것!

shimdh 2025. 10. 8. 21:20
728x90

React는 현대 웹 개발에서 사용자 인터페이스를 구축하는 데 필수적인 도구입니다. 그 핵심에는 바로 '컴포넌트'가 있습니다. 컴포넌트는 UI의 독립적이고 재사용 가능한 조각으로, 자체적인 상태와 동작을 관리하며 애플리케이션의 견고함과 효율성을 결정짓는 요소입니다. 이 글에서는 React 컴포넌트의 두 가지 주요 유형인 함수형 컴포넌트와 클래스형 컴포넌트를 심도 있게 비교하고, React 16.8부터 도입되어 개발 방식에 혁명적인 변화를 가져온 '훅(Hooks)'의 중요성과 활용법에 대해 자세히 알아보겠습니다.

컴포넌트란 무엇인가? 왜 중요한가?

React에서 컴포넌트는 애플리케이션의 핵심 구성 요소입니다. 마치 레고 블록처럼, 각 컴포넌트는 특정 기능을 수행하며 독립적으로 동작합니다. 이는 개발자가 UI를 작고 관리하기 쉬운 단위로 분해하여 개발할 수 있게 함으로써 코드의 재사용성을 높이고 유지보수를 용이하게 만듭니다. 강력하고 효율적인 React 애플리케이션을 개발하려면 컴포넌트를 효과적으로 생성하고 활용하는 방법을 깊이 이해하는 것이 필수적입니다.

728x90

React 컴포넌트의 두 가지 얼굴: 함수형 vs. 클래스형

React 컴포넌트는 크게 두 가지 종류로 나뉩니다. 각각의 장단점을 이해하는 것은 적절한 상황에 맞는 컴포넌트를 선택하고 더 나은 코드를 작성하는 데 큰 도움이 됩니다.

1. 함수형 컴포넌트: 간결함과 훅의 시너지

함수형 컴포넌트는 JSX(JavaScript XML)를 반환하는 단순한 JavaScript 함수입니다. React 초기에는 주로 '프레젠테이셔널 컴포넌트'(Presentational Component)라고 불리며, 단순히 props를 받아 UI를 렌더링하는 데 사용되었습니다. 하지만 React 16.8에서 '훅(Hooks)'이 도입되면서 함수형 컴포넌트의 위상은 완전히 달라졌습니다.

특징:

  • 구조가 간결하고 가독성이 뛰어납니다.
  • 클래스 컴포넌트에 비해 보일러플레이트 코드가 적습니다.
  • 훅을 통해 상태 관리(useState) 및 생명 주기 기능(useEffect)에 접근할 수 있게 되었습니다.

예시:

function Greeting(props) {
    return <h1>안녕하세요, {props.name}님!</h1>;
}

2. 클래스형 컴포넌트: 강력한 생명 주기 제어

클래스형 컴포넌트는 React.Component를 상속받아 생성되는 컴포넌트입니다. 과거에는 상태 관리나 생명 주기 메서드가 필요한 경우 주로 사용되었습니다.

특징:

  • render() 메서드를 반드시 포함해야 합니다.
  • state 객체를 통해 내부 상태를 관리합니다.
  • 다양한 생명 주기 메서드(예: componentDidMount, componentDidUpdate, componentWillUnmount)를 포함하여 컴포넌트의 생명 주기 전반에 걸쳐 복잡한 로직을 처리할 수 있습니다.

예시:

class Greeting extends React.Component {
    render() {
        return <h1>안녕하세요, {this.props.name}님!</h1>;
    }
}

컴포넌트의 생명 주기 메서드 이해하기

클래스형 컴포넌트에서 제공하는 생명 주기 메서드는 컴포넌트가 DOM에 마운트(삽입), 업데이트, 언마운트(제거)되는 과정의 특정 시점에 개발자가 개입하여 원하는 작업을 수행할 수 있도록 해주는 강력한 도구입니다.

  • componentDidMount(): 컴포넌트가 DOM에 마운트된 직후에 호출됩니다. 데이터 가져오기(fetching data), 이벤트 리스너 설정, D3.js나 Three.js 같은 외부 라이브러리 연동 등에 유용합니다.
  • componentDidUpdate(prevProps, prevState): 컴포넌트가 업데이트된 직후에 호출됩니다. props나 state 변경에 따른 추가 작업을 수행할 때 사용됩니다. 이전 props와 state를 인자로 받아 현재 값과 비교하여 특정 조건에서만 동작하도록 할 수 있습니다.
  • componentWillUnmount(): 컴포넌트가 DOM에서 제거되기 직전에 호출됩니다. componentDidMount에서 설정했던 타이머, 이벤트 리스너, 구독 등을 해제하여 메모리 누수를 방지하는 데 필수적입니다.

예시:

class Timer extends React.Component {
    componentDidMount() {
        this.interval = setInterval(() => this.tick(), 1000);
    }

    componentWillUnmount() {
        clearInterval(this.interval);
    }

    tick() {
        // 여기서 상태를 업데이트하거나 다른 작업을 수행합니다.
    }

    render() {
        return <div>타이머</div>;
    }
}

React의 혁신, 훅(Hooks) 완전 정복

React 16.8에서 도입된 훅은 함수형 컴포넌트에서도 상태 관리(useState) 및 부수 효과(useEffect)와 같은 클래스 컴포넌트의 기능을 사용할 수 있도록 합니다. 이는 React 개발 방식에 큰 변화를 가져왔으며, 이제 대부분의 새로운 React 개발은 함수형 컴포넌트와 훅을 기반으로 이루어집니다.

주요 훅 자세히 살펴보기

1. useState 훅: 함수형 컴포넌트에 상태 불어넣기

useState 훅은 함수형 컴포넌트에 상태 관리 기능을 추가할 수 있도록 합니다. 이 훅은 상태 변수와 해당 상태를 업데이트하는 함수를 배열 형태로 반환합니다.

사용법: const [state, setState] = useState(initialState);

  • state: 현재 상태 값
  • setState: 상태를 업데이트하는 함수
  • initialState: 상태의 초기 값 (최초 렌더링 시에만 사용됨)

예시:

import { useState } from 'react';

function Counter() {
    const [count, setCount] = useState(0);

    return (
        <div>
            <p>당신은 {count}번 클릭했습니다</p>
            <button onClick={() => setCount(count + 1)}>클릭하세요</button>
        </div>
    );
}

2. useEffect 훅: 부수 효과(Side Effect) 효율적으로 관리하기

useEffect 훅은 데이터 가져오기, 이벤트 구독, DOM 직접 조작과 같은 '부수 효과'를 컴포넌트 렌더링 후에 처리하는 데 사용됩니다. 이는 클래스 컴포넌트의 componentDidMount, componentDidUpdate, componentWillUnmount의 기능을 한 곳에서 처리할 수 있게 해줍니다.

사용법: useEffect(callback, [dependencies]);

  • callback: 부수 효과를 수행할 함수. 이 함수는 컴포넌트가 렌더링될 때마다 실행되지만, 의존성 배열에 따라 재실행 여부를 제어할 수 있습니다. 클린업(cleanup) 함수를 반환할 수 있어 componentWillUnmount와 같은 역할을 수행합니다.
  • [dependencies]: 의존성 배열. 이 배열에 포함된 값들이 변경될 때만 callback 함수가 다시 실행됩니다.
    • 빈 배열([]): 컴포넌트가 처음 마운트될 때 한 번만 실행되고, 언마운트될 때 클린업 함수가 실행됩니다 (클래스 컴포넌트의 componentDidMount, componentWillUnmount와 유사).
    • 생략: 컴포넌트가 렌더링될 때마다 callback 함수가 실행됩니다.

예시:

import { useEffect, useState } from 'react';

function DataFetcher({ url }) {
    const [data, setData] = useState(null);

    useEffect(() => {
        fetch(url)
            .then(response => response.json())
            .then(data => setData(data));
    }, [url]); // url이 변경될 때만 실행됩니다.

    return data ? <pre>{JSON.stringify(data)}</pre> : null;
}
728x90