티스토리 뷰

1. 개요

 리액트로 작업할 때, 만들어진지 좀 된 컴포넌트를 수정해야하는 경우가 자주 있다. 그리고 이런 컴포넌트들 중에는 함수형 컴포넌트가 아닌, 클래스형 컴포넌트로 구성된 것들이 꽤나 많다. 리액트의 생명주기, 생명주기 메서드에 대해서 이론적으로 배운 적은 있어도 실제로 클래스형 컴포넌트를 접하고 작업한지는 오래되지 않았기에, 가끔 각 메서드에 대해 헷갈릴 때가 있다. 그렇기에 자주 사용되는 메서드를 간단하게 기록해보려고 한다.

 

2. componentDidMount()

  •  컴포넌트가 마운트된(처음 화면에 렌더링된) 직후 실행된다. 즉, 처음 한 번만 실행된다.
  • 주로 API 요청을 보내거나, DOM을 조작하거나, 여러 비동기 작업을 실행하거나, 이벤트 리스너를 등록하는 데에 이용된다.
  • 예시 코드
class MyComponent extends React.Component {
  componentDidMount() {
    console.log("컴포넌트가 마운트됨!");
  }

  render() {
    return <div>안녕하세요!</div>;
  }
}

 

3. componentDidUpdate(prevProps, prevState)

  • 컴포넌트의 props 혹은 state가 업데이트된(혹은 리렌더링된) 직후 실행된다.
  • 초기 렌더링 때는 실행되지 않는다.
  • 주로 props, state 변경 감지 후 추가 작업을 하거나 변경된 값을 기반으로 API를 요청할 때 이용된다.
  • 만약 componentDidUpdate 내부에서 setState를 호출할 경우, 잘못하면 무한 루프에 빠질 수 있으므로 주의해야 한다.
    • 이는 prevProps, prevState를 이용하여 방지할 수도 있다.
  • 예시 코드
class MyComponent extends React.Component {
  state = { count: 0 };

  componentDidUpdate(prevProps, prevState) {
    if (prevState.count !== this.state.count) {
      console.log(`count가 변경됨: ${this.state.count}`);
    }
  }

  render() {
    return (
      <div>
        <p>Count: {this.state.count}</p>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          증가
        </button>
      </div>
    );
  }
}

 

 

4. componentWillUnmount()

  • 컴포넌트가 언마운트(화면에서 사라지기) 직전에 실행된다.
  • setTimeout, setInterval 등을 제거하거나, 이벤트 리스너를 제거하거나, 여러 구독을 해제하는 데에 이용된다.
  • 예시 코드
class MyComponent extends React.Component {
  componentDidMount() {
    this.timer = setInterval(() => {
      console.log("1초마다 실행됨");
    }, 1000);
  }

  componentWillUnmount() {
    clearInterval(this.timer);
    console.log("컴포넌트가 언마운트됨! 타이머 정리 완료");
  }

  render() {
    return <div>안녕하세요!</div>;
  }
}

 

5. shouldComponentUpdate(nextProps, nextState)

  • 컴포넌트가 업데이트될지를 결정하는 메서드로, 컴포넌트가 업데이트될 때(props, state가 변경될 때) 실행된다.
  • 리렌더링 직전에 실행되며, true를 return할 경우 리렌더링하지만, (특정 조건에서) false를 return할 경우 리렌더링을 막을 수 있다.
  • 즉, shouldComponentUpdate가 false를 return할 경우 render(), componentDidUpdate()가 실행되지 않는다.
  • 기본값은 항상 true를 return한다.
  • 대부분의 경우, React.PureComponent를 사용하면 shouldComponentUpdate를 직접 구현할 필요가 없다고 한다.
    • PureComponent는 기본적으로 props와 state의 얕은 비교를 수행해 최적화를 해준다고 한다.
  • 예시 코드
class MyComponent extends React.Component {
  state = { count: 0 };

  shouldComponentUpdate(nextProps, nextState) {
    // count 값이 홀수일 때만 리렌더링 허용
    if (nextState.count % 2 === 1) {
      return true; // 리렌더링 진행
    }
    return false; // 리렌더링 방지
  }

  handleClick = () => {
    this.setState({ count: this.state.count + 1 });
  };

  render() {
    console.log("🔄 리렌더링 됨!");
    return (
      <div>
        <p>Count: {this.state.count}</p>
        <button onClick={this.handleClick}>증가</button>
      </div>
    );
  }
}

 

// PureComponent 예시 코드
class MyComponent extends React.PureComponent {
  render() {
    console.log("🔄 리렌더링 됨!");
    return <div>{this.props.value}</div>;
  }
}

 

 

6. 함수형 컴포넌트에서 적용할 때는

  • componentDidMount: useEffect(() => { ... }. []);
  • componentDidUpdate: useEffect(() => { ... }, [state 혹은 props]);
  • componentWillUnmount: useEffect(() => { return () => { ... } }, [])
  • shouldComponentUpdate: React.memo, 추가적으로 useCallback을 이용

 

6-1. React.memo를 이용해서 shouldComponentUpdate를 구현한 경우

import React from "react";

const MyComponent = React.memo(({ value }) => {
  console.log("🔄 리렌더링됨!");
  return <div>Value: {value}</div>;
});

export default MyComponent;

 

  • React.memo는 기본적으로 props의 얕은 비교를 수행하여 변경 여부를 판단, props가 변경되지 않으면 리렌더링을 방지하는 역할을 한다.
  • 위 코드에서 value가 변경될 때만 리렌더링이 발생한다.

 

6-2. React.memo와 useCallback을 이용한 경우

import React, { useState, useCallback } from "react";

const ChildComponent = React.memo(({ onClick }) => {
  console.log("🔄 자식 컴포넌트 리렌더링됨!");
  return <button onClick={onClick}>클릭</button>;
});

const ParentComponent = () => {
  const [count, setCount] = useState(0);

  const handleClick = useCallback(() => {
    console.log("버튼 클릭!");
  }, []); // 빈 배열이므로 handleClick은 한 번만 생성됨

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>증가</button>
      <ChildComponent onClick={handleClick} />
    </div>
  );
};

export default ParentComponent;

 

  • useCallback은 리렌더링 간에 함수 정의를 캐싱해주는 훅으로, 함수 자체가 불필요하게 다시 생성되지 않게 방지할 수 있다.
  • 위 코드에서 ParentComponent가 리렌더링되어도, handleClick은 useCallback을 통해 재생성되지 않는다.
  • ChildrenComponent는 React.memo에 의해 props가 변경되지 않으면 리렌더링되지 않는다.

 

6-3. useMemo를 이용한 경우

import React, { useState, useMemo } from "react";

const ExpensiveCalculation = ({ number }) => {
  const result = useMemo(() => {
    console.log("🧮 복잡한 계산 실행!");
    return number * 2;
  }, [number]); // number가 변경될 때만 계산 실행

  return <div>계산 결과: {result}</div>;
};

const ParentComponent = () => {
  const [count, setCount] = useState(0);
  const [number, setNumber] = useState(1);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>카운트 증가</button>
      <button onClick={() => setNumber(number + 1)}>숫자 증가</button>
      <ExpensiveCalculation number={number} />
    </div>
  );
};

 

  • useMemo리렌더링 사이에 계산 결과를 캐싱할 수 있게 해주는 훅으로, 컴포넌트가 리렌더링될 때 값이 다시 계산되지 않게 최적화하는 역할을 한다.
  • 위 코드에서 number가 변경될 때만 useMemo가 실행되며, count가 변경되어도 ExpensiveCalculation의 불필요한 재계산을 방지할 수는 있다.
  • 이를 통해 불필요한 렌더링을 줄일 수 있기는 있다.

 

6-4. 함수형 컴포넌트에서의 shouldComponentUpdate에 대한 결론

클래스형 (shouldComponentUpdate) 함수형 (React.memo & useMemo & useCallback)
리렌더링 여부를 수동으로 제어 자동으로 최적화
shouldComponentUpdate 메서드를 오버라이드 React.memo()로 최적화
prevProps/prevState 비교 필요 useMemo, useCallback으로 값 & 함수 재사용

 

  • React.memo, useMemo, useCallback을 적절히 사용하면 최적화 효과를 극대화할 수 있긴 있지만, 적재적소에 사용하는 것이 좋다.

 

7. 리액트 생명주기 이미지

 


참고한 문서

 

Component – React

The library for web and native user interfaces

ko.react.dev

 

PureComponent – React

The library for web and native user interfaces

ko.react.dev

 

useCallback – React

The library for web and native user interfaces

ko.react.dev

 

useMemo – React

The library for web and native user interfaces

ko.react.dev

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
글 보관함