React

컴포넌트 (클래스형 vs 함수형)

doonii 2025. 1. 9. 18:05

컴포넌트란?

  • HTML 요소를 반환하는 JavaScript 함수 또는 클래스
  • UI를 구성하는 독립적이고 재사용 가능한 코드 조각

 

컴포넌트의 핵심 개념

1. props (속성)

  • 부모 컴포넌트에서 자식 컴포넌트로 데이터를 전달하는 방식
  • 읽기 전용이며 컴포넌트 내부에서 변경할 수 없다.
function Child(props) {
  return <div>{props.message}</div>;
}

function Parent() {
  return <Child message="안녕하세요!" />;
}

 

2. state (상태)

  • 컴포넌트 내부에서 관리되는 데이터
  • 함수형 컴포넌트에서는 useState 훅을 사용해 관리한다.
function Counter() {
  const [count, setCount] = useState(0);
  
  return (
    <div>
      <p>현재 카운트: {count}</p>
      <button onClick={() => setCount(count + 1)}>
        증가
      </button>
    </div>
  );
}

3. 생명주기

  • 컴포넌트가 생성(mount)되고, 업데이트(update)되고, 제거(unmount)되는 과정
  • 함수형 컴포넌트에서는 useEffect 훅으로 관리된다.
function Example() {
  useEffect(() => {
    console.log('컴포넌트가 마운트되었습니다');
    
    return () => {
      console.log('컴포넌트가 언마운트됩니다');
    };
  }, []);
}

 

 

컴포넌트 활용의 장점

  • 한번 만든 컴포넌트는 여러 곳에서 재사용이 가능해 개발 효율이 향상된다.
  • 독립적인 단위로 관리되어 코드를 체계적으로 관리할 수 있고 유지보수가 용이하다.

 

컴포넌트를 정의하는 두가지 주요 방법

클래스형 컴포넌트

  • ES6 클래스를 사용하여 정의되며, React.Component 클래스를 상속받는다.
  • React 초기부터 사용된 전통적인 방식으로 리액트 훅이 도입된 이후 현재는 함수형 컴포넌트 사용이 권장된다.
  • this 키워드를 사용하고 생명주기 메서드(lifecycle methods)를 통해 상태를 관리할 수 있다.
class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      // 초기 상태
    };
  }

  render() {
    return (
      <div>
        {/* JSX */}
      </div>
    );
  }
}

 

함수형 컴포넌트

  • JavaScript 함수로 정의되며, props를 인자로 받아 React 엘리먼트를 반환한다.
  • 클래스형보다 더 간결하고 이해하기 쉬운 문법을 가지며 메모리 자원을 클래스형 컴포넌트보다 덜 사용한다.
  • React 16.8 이후 도입된 Hooks를 사용해 상태 관리와 생명주기 기능을 구현할 수 있다.
function MyComponent(props) {
  // hooks 사용
  const [state, setState] = useState(initialState);
  
  return (
    <div>
      {/* JSX */}
    </div>
  );
}

 

 

클래스형 컴포넌트의 생명주기 메서드

render()

  • 클래스 컴포넌트의 유일한 필수 메서드
  • 컴포넌트 UI를 렌더링하기 위해 사용
  • 마운트, 업데이트 과정에서 호출된다.
  • 순수함수여야 하며 동일한 입력(props, state)에 대해 동일한 출력(React 엘리먼트)을 반환해야 한다.

 

componentDidMount()

  • 컴포넌트가 마운트되고 준비되는 즉시 실행
  • 주로 API 호출, 구독 설정, DOM 조작 등의 작업에 사용
componentDidMount() {
  // API 호출
  fetch('api/data')
    .then(response => response.json())
    .then(data => this.setState({ data }));
}

 

 

componentDidUpdate()

  • 컴포넌트 업데이트 직후 실행
  • props나 state 변화에 따른 DOM 업데이트에 사용

 

componentWillUnmount()

  • 컴포넌트 제거 직전에 호출
  • 클린업 작업 수행(타이머 제거, 네트워크 요청 취소, 구독 해제)
componentWillUnmount() {
  clearInterval(this.timer);
  this.subscription.unsubscribe();
}

 

 

성능 최적화 관련 메서드

shouldComponentUpdate()

  • 불필요한 리렌더링 방지를 위해 사용
  • 성능 최적화 상황에서만 사용 권장됨

 

static getDerivedStateFromProps()

  • render() 호출 직전에 실행
  • static 메서드로 this 접근 불가

 

getSnapShotBeforeUpdate()

  • DOM 업데이트 직전 호출
  • 윈도우 크기 조절이나 스크롤 위치 등 DOM 정보 저장에 유용

 

에러 처리 메서드

getDerivedStateFromError()

  • 자식 컴포넌트 에러 발생 시 호출
  • 에러 UI 표시를 위한 상태 업데이트

 

 

componentDidCatch()

  • 에러 발생 후 호출
  • 에러 로깅 등에 사용

 

클래스 컴포넌트의 두 가지 유형

Component

  • 기본 React 컴포넌트
  • state 변경 시 즉시 리렌더링됨

PureComponent

  • 얕은 비교 후 결과가 다를 때만 렌더링 (자동 성능 최적화)
  • 단순한 props와 state에 적합
    • 얕은 비교만 수행하기 때문에 객체와 같은 복잡한 구조의 데이터 변경은 감지하지 못하므로 제대로 작동하지 않을 수 있다.

 

클래스 컴포넌트의 한계

  • 데이터 흐름 추적이 어려움
    • 여러 메서드에서 state의 업데이트가 일어날 수 있고, 생명주기 메서드의 순서 관리가 필요하다.
  • 내부 로직의 재사용이 어려움
    • 또 다른 고차 컴포넌트로 감싸거나 props를 넘겨줘야하는데, 이때 wrapper hell(래퍼 지옥)이 발생할 수 있음
  • 컴포넌트 크기 증가
  • 번들링 최적화 어려움
  • 핫 리로딩 불리
    • hot reloading : 코드에 변경 사항 발생 시 앱 재시작 없이도 변경된 코드만 빠르게 업데이트하는 기법

 

함수컴포넌트와 클래스 컴포넌트의 차이

생명주기 관리

  • 함수형 : useEffect 훅으로 관리
  • 클래스형 : 생명주기 메서드 사용
// 함수형
useEffect(() => {
  // componentDidMount, componentDidUpdate
  return () => {
    // componentWillUnmount
  };
}, []);

// 클래스형
componentDidMount() {
  // 마운트 시 실행
}

 

렌더링 값 처리

  • 함수형 : 렌더링 시점의 값 보전
  • 클래스형 : this 를 통한 최신 값 참조

 

성능 최적화

  • 함수형 : useMemo, useCallback, React.memo
  • 클래스형 : shouldComponentUpdate, PureComponent
// 함수형
const MemoizedComponent = React.memo(function MyComponent(props) {
  // ...
});

// 클래스형
class MyComponent extends React.PureComponent {
  // ...
}

 

 

함수형 컴포넌트가 권장되는 이유?

  • 코드가 간결하고 재사용성이 용이하다.
    • 불필요한 보일러플레이트 코드를 줄일 수 있어 개발 효율성이 향상된다.
  • 훅을 통해 상태관리를 유연하게 할 수 있다.
  • 인스턴스를 생성하지 않아 메모리 사용량이 적으므로 성능이 향상된다.
  • React 공식 문서에서도 함수형 컴포넌트와 Hooks 사용을 권장하고 있음