컴포넌트 라이프사이클

2024. 4. 12. 13:51·React

라이프사이클 단계

리액트 생명주기는 크게 3단계로 나눌 수 있습니다.

Mounting → Updating → Unmounting

각 생명주기에는 순차적으로 실행되는 메서드들이 있습니다.

각 생명주기 마다 메서드의 순서대로 상세설명을 진행하겠습니다.

 

Mounting

DOM에 Node를 추가하는(컴포넌트가 화면에 나타는) 작업입니다.

메서드는 다음과 같은 순으로 진행됩니다.

constructor → getDerivedStateFromProps → render → componentDidMount

 

1. constructor(생성자)

  • 리액트에서 생성자는 컴포넌트가 생성될 때(DOM에 추가되기 전) 실행됩니다.
  • 초기 상태(state)를 설정합니다.

2. getDerivedStateFromProps

  • React 17부터 사용합니다(componentWillReciveProps 대체).
  • 컴포넌트가 마운트될때 한번 호출됩니다.
    *업데이팅 단계에서는 nextProps.value와 prevState.value를 비교 후 변경되었으면 호출됩니다.
  • props에 의존하는 state를 쓰고 싶은(props를 그대로 state로 쓰고싶은) 경우 사용합니다.
    *일반적으로는 props와 state를 명확하게 분리하여 사용하는 것이 좋습니다.
  • getDerivedStateFromProps의 return값이 해당 컴포넌트의 this.state에 저장됩니다.
// 클래스형 컴포넌트
class MyComponent extends React.Component {
	// 마운트 시: componentDidMount처럼 한번만 호출됩니다.
	// 업데이팅 시: nextProps.value !== prevState.value 일때만 호출됩니다.
  static getDerivedStateFromProps(nextProps) {
    return {
      **derivedValue**: nextProps.value
    };
  }
  render() {
    <div>{this.state.**derivedValue**}</div>
  }
}

// 함수형 컴포넌트 사용시 동일한 기능 구현 하려면
function MyComponent({value}) {
  const [**derivedValue**, setDerivedValue] = useState(null);
  useEffect(() => {
    setDerivedValue(value);
  }, [value]);
  return <div>{**derivedValue**}</div>;
}

3. render

  • 순수하게 컴포넌트의 UI 표현을 반환하는 역할을 수행해야 합니다
  • 1) 외부 상태 변경이나 부작용을 일으키는 작업은 2) 다른 메서드에서 처리되어야 합니다
    *1) setState, 비동기 처리 등
    *2) render가 아닌 다른 life-cycle 메서드, 이벤트 핸들러 등

4. componentDidMount

  • 컴포넌트가 처음으로 화면에 마운트된 후에 실행되며, 이후에는 다시 호출되지 않습니다.
  • 주로 초기 데이터 로딩, 외부 API 호출, 이벤트 리스너 등록 등의 작업을 수행합니다.

Updating

컴포넌트의 상태(state)나 속성(props)이 변경되었을 때 발생합니다.

메서드는 다음과 같은 순으로 진행됩니다.

getDerivedStateFromProps → shouldComponentUpdate → render → componentDidUpdate

1. getDerivedStateFromProps

  • nextProps.value와 prevState.value를 비교 후 변경되었으면 호출됩니다.
  • 나머지 내용은 마운팅 단계 와 동일합니다.

2. shouldComponentUpdate

  • 현재 상태(state)와 현재 속성(props)이 변경되었을 때 컴포넌트 리렌더링 여부를 결정할 수 있습니다.
    *리렌더링 여부를 결정한다는 것은, 리렌더링 시킬수도, 안시킬 수도 있다는 것입니다.
      예를들면, 특정 state와 props가 변했을 때만 리렌더링 시킬 수 있습니다.
// 클래스형 컴포넌트
class MyComponent extends React.Component {
  shouldComponentUpdate(nextProps, nextState) {
		// true 리턴: value 속성이 변경되지 않았으므로 리렌더링 수행 X
		// false 리턴: value 속성이 변경되었으므로 리렌더링 수행 O
    return prevProps.value === nextProps.value;
  render() {
    // 렌더링 로직
  }
}

// 함수형 컴포넌트 사용시 동일한 기능 구현 하려면
const MyComponent = React.memo((props) => {
  // 컴포넌트 로직
  return (
    // JSX
  );
}, (prevProps, nextProps) => {
  return prevProps.value === nextProps.value;
});

3. render

  • 호출되는 상황은 다음과 같습니다.
    • 컴포넌트의 props 또는 state가 변경되었을 때
    • shouldComponentUpdate 메서드가 true를 반환했을 때
    • getDerivedStateFromProps 메서드가 조건에 따라 호출된 후
  • 나머지 내용은 마운팅 단계 와 동일합니다.

4. componentDidUpdate

  • 컴포넌트의 업데이트가 완료된 후에 호출됩니다.
  • componentDidUpdate는 최초 렌더링 시에는 호출되지 않습니다.
  • 이전의 속성(props)과 상태(state)에 접근할 수 있습니다.
    • 업데이트 전후의 차이를 비교하거나, 추가적인 동작을 수행할 수 있습니다.
// 클래스형 컴포넌트 
componentDidUpdate(prevProps, prevState) {
  // props.value 변경여부 확인
  if (prevProps.value !== this.props.value) {
    const element = document.getElementById('myElement');
    element.style.transform = 'scale(1.2)';
  }
}

// 함수형 컴포넌트 사용시 동일한 기능 구현 하려면
function MyComponent(props) {
	// useRef는 리렌더 되어도 값을 유지하므로 prevValue로 사용할 수 있습니다.
	const prevValueRef = useRef(props.value);
	useEffect(() => {
	  if (prevValueRef.current !== props.value) {
	    const element = document.getElementById('myElement');
	    element.style.transform = 'scale(1.2)';
	  }
	  // 이전 props를 현재 props로 업데이트합니다.
	  prevValueRef.current = props.value;
	}, [props.value]);
	return (
		// JSX
	);
}

Unmount

컴포넌트가 DOM에서 제거되는 단계입니다.

메서드는 componentWillUnmount 하나입니다.

1. componentWillUnmount

  • 더 이상 필요하지 않은 모든 정리 작업을 수행하는 데 사용합니다.
// 클래스형 컴포넌트
class MyComponent extends React.Component {
  componentDidMount() {
    this.intervalId = setInterval(
			()=> console.log('1초마다 출력'), 1000
		);
  }
  componentWillUnmount() {
    clearInterval(this.intervalId);
  }
  render() {
    // 렌더링 로직
  }
}

//
function MyComponent() {
  useEffect(() => {
    const intervalId = setInterval(() => console.log('1초마다 출력'), 1000);
    return () => {
      clearInterval(intervalId); // unmount
    };
  }, []);
  return (
		// JSX
	);

 

 

 

 

 

 

 

 

 

 

 

[참고자료]

리액트 생명주기

저작자표시 비영리 변경금지 (새창열림)

'React' 카테고리의 다른 글

React 18 주요 변경점  (0) 2024.04.15
검색 기능 구현 시 고려사항(API 호출 시점, debouncing)  (0) 2024.04.15
Redux → SWR(2): SWR로 Redux 대체 가능한가?  (0) 2024.04.13
Redux → SWR(1): Redux의 한계  (1) 2024.04.13
Flux 아키텍쳐  (0) 2024.04.11
'React' 카테고리의 다른 글
  • 검색 기능 구현 시 고려사항(API 호출 시점, debouncing)
  • Redux → SWR(2): SWR로 Redux 대체 가능한가?
  • Redux → SWR(1): Redux의 한계
  • Flux 아키텍쳐
URE
URE
Skill: Javascript, ReactJS, Next.js, React Native ... *블로그 이전 작업(24. 04. 11 ~ 24. 04. 15)
  • URE
    Dev++
    URE
  • 전체
    오늘
    어제
    • 분류 전체보기 (51)
      • Browser (6)
      • OS (1)
      • Javascript (14)
      • React (19)
      • Next.js (4)
      • React Native (0)
      • Architecture (1)
      • Network (3)
      • 스크랩 (3)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    react concurrent
    react
    자바스크립트
    원시타입
    리덕스
    swr
    TCP
    IP
    브라우저
    react18
    dataFetching
    리액트 코어
    JS
    상태관리라이브러리
    URL
    참조타입
    Port
    javascript
    리액트
    Redux
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
URE
컴포넌트 라이프사이클
상단으로

티스토리툴바