본문 바로가기

3주차

리액트 컴포넌트의 Lifecycle

안녕하세요 ~ 웹 YB 김가현입니다.

3주차 공유과제로는 리액트 컴포넌트의 생명주기를 다뤄 보려고 해요 !

 

리액트의 컴포넌트에는 크게 함수형 컴포넌트와 클래스형 컴포넌트가 있는데,

예전에는 상태 관리나 생명 주기 관련 기능을 사용하려면 반드시 클래스형 컴포넌트를 사용해야 했어요.

하지만 리액트 16.8 버전 이후로 Hook이 도입되면서 함수형 컴포넌트에서도 클래스형 컴포넌트가 제공하는 기능을 쓸 수 있게 되었답니다

짱이죠 ?

 

함수형 컴포넌트의 생명주기 ! 라이프사이클에 대해 알아보겠습니다 🫡


Lifecycle ?

React 컴포넌트의 라이프 사이클은 컴포넌트의 생성, 업데이트, 제거 과정에서 일어나는 일련의 단계를 의미한다.

  1. 마운트
    • 컴포넌트가 처음으로 생성될 때
    • 컴포넌트의 초기화 작업을 수행하거나 외부 데이터를 가져와 초기 상태를 설정
  2. 업데이트
    • 컴포넌트가 새로운 props나 state를 받아 갱신될 때
    • 컴포넌트의 상태 변화에 따른 UI 업데이트 작업을 처리
  3. 언마운트
    • 컴포넌트가 제거되기 전 발생
    • 컴포넌트 내부의 정리 작업이나 리소스 해제 등 컴포넌트가 더이상 필요하지 않을 때의 작업을 처리

 

클래스형 컴포넌트의 Lifecycle

 

먼저 클래스형 컴포넌트의 라이프사이클에 대해 알아보자 …

뭔가 복잡하다

component가 mount 되기 시작하면

  1. constructor 실행
  2. getDerivedStateFromProps에서 props와 state를 비교
  3. render component
  4. update DOM
  5. componentDidMount 실행

component가 update 될 때 (new props or setState)

  1. getDerivedStateFromProps에서 props와 state 비교
  2. shouldComponentUpdate 실행 → new props, state를 확인하고 rerender 할 것인지 결정
  3. rerender
  4. update DOM
  5. componentDidUpdate 실행

component가 unmount 될 때

  1. componentWillUnmount 실행

세줄요약

  1. 최초 : constructor -> getDerivedStateFromProps -> componentDidMount
  2. 업데이트 : getDerivedStateFromProps -> componentDidUpdate
  3. 언마운트 : componentWillUnmount

Hook에서는 useEffet()가 위 생명주기 함수들을 대체한다 !

 

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

분류 클래스형 컴포넌트 함수형 컴포넌트
Mounting constructor() 함수형 컴포넌트 내부
Mounting render() return()
Mounting componentDidMount() useEffect()
Updating componentDidUpdate() useEffect()
UnMounting componentWillUnmount() useEffect()의 return

 

 

useEffect()로 생명주기 함수를 구현해보자 ~!

useEffect는 componentDidMount()  + ComponentDidUpdate() + componentWillUnMount() 의 기능을 합친 것이다.

(by 공식문서)

따라서 우리는 useEffect()를 통해 각각의 기능을 구현할 수 있다.

 

UseEffect 문법에 대한 설명은 이곳을 참고하세요 👊🏻

 

 

1. Mounting - 생성

import React, { useState, useEffect } from 'react';

const FuncComponentLifeCycle = () => {

  const [num, setNum] = useState(1);
  const handleClick = () => {
    setNum(num + 1);
  };

  // 1. 함수형 컴포넌트 내부 로직
  // 컴포넌트 호출 시 가장 먼저 실행되는 코드
  console.log('함수형 컴포넌트 내부 로직');

  // 3. useEffect
  // 렌더링 이후 !!!!!! 에 실행된다
  useEffect(() => {
    console.log('useEffect called 😶');
  }, []);


  // 2. return
  // 미리 구현한 HTML을 화면에 렌더링 
  return (
    <div>
      <h1>{num}</h1>
      <button onClick={handleClick}>+ 1</button>
    </div>
  );
};

export default FuncComponentLifeCycle;

 

이렇게 로그가 찍히는 것을 확인 할 수 있다.

deps 파라미터가 빈 배열이기 때문에 렌더링 이후 최초 한 번만 실행이 된다

 

 

2. Updating - 생성

import React, { useState, useEffect } from 'react';

const FuncComponentLifeCycle = () => {

  const [num, setNum] = useState(1);
  const handleClick = () => {
    setNum(num + 1);
  };

  // 1. 함수형 컴포넌트 내부 로직
  // 컴포넌트 호출 시 가장 먼저 실행되는 코드
  console.log('함수형 컴포넌트 내부 로직');

  // 3. useEffect
  useEffect(() => {
    console.log('useEffect called 😶');
  }, [num]); // [] -> [num] 으로 변경하면 num이 update 될 때마다 매번 실행된다 


  // 2. return
  // 미리 구현한 HTML을 화면에 렌더링 
  return (
    <div>
      <h1>{num}</h1>
      <button onClick={handleClick}>+ 1</button>
    </div>
  );
};

export default FuncComponentLifeCycle;

 

useEffect의 의존성 배열을 [num]으로 설정했기 때문에, num이 변경될 때마다 useEffect가 실행되어 위와 같이 출력된다. 

 

 

3. UnMounting - 제거

import React, { useState, useEffect } from 'react';

const ChildComponent = () => {
  useEffect(() => {
    console.log('ChildComponent Mounted');
    
    return () => {
      console.log('ChildComponent Unmounted');
    };
  }, []);

  return <div>안녕 ~</div>;
};

const FuncComponentLifeCycle = () => {
  const [num, setNum] = useState(1);
  const [showChild, setShowChild] = useState(true);

  const handleClick = () => {
    setNum(num + 1);
  };

  const toggleChild = () => {
    setShowChild(!showChild);
  };

  console.log('함수형 컴포넌트 내부 로직');

  useEffect(() => {
    console.log('FuncComponentLifeCycle useEffect called 😶');
    return () => {
      console.log('FuncComponentLifeCycle Unmount');
    };
  }, []);

  return (
    <div>
      <button onClick={toggleChild}>Click !</button>
      {showChild && <ChildComponent />}
    </div>
  );
};

export default FuncComponentLifeCycle;

 

최초 화면에는 Click 버튼 밑에 '안녕 ~'이라는 문구가 있다가 버튼을 누르면 사라진다. 

위 이미지는 해당 동작을 수행했을 때의 콘솔 창이다.

실행 순서대로 보면,

 

1) FuncComponentLifeCycle 처음 렌더링될

  • "FuncComponentLifeCycle 내부 로직" -> 컴포넌트가 처음 호출될 때 출력
  • "ChildComponent Mounted" -> ChildComponent가 마운트될 때 출력
  • "FuncComponentLifeCycle useEffect called 😶" -> FuncComponentLifeCycle의 useEffect가 처음 실행될 때 출력

왜 FuncComponentLifeCycle useEffect called 😶보다 ChildComponent Mounted 가 먼저 출력되는가 ?

  • React는 컴포넌트 렌더링시 JSX를 해석하여 DOM을 구성하는데 이 과정에서 각 컴포넌트의 렌더링이 완료되면 그 안에 포함된 하위 컴포넌트도 렌더링한다.
  • 그래서 FuncComponentLifeCycle가 렌더링될 때 ChildComponent도 렌더링되고, 이 시점에서 ChildComponent Mounted 메시지가 출력

2) 버튼을 눌러 showChild 상태를 변경할 때

Click ! 버튼을 클릭하면 toggleChild 함수가 호출되어 showChild 상태가 false로 바뀐다

  • sshowChild가 false로 변경되면, FuncComponentLifeCycle 컴포넌트가 재렌더링되며 FuncComponentLifeCycle 내부 로직 메시지가 출력 (아직 ChildComponent가 DOM에서 제거되지 않음)
  • ChildComponent를 언마운트 -> ChildComponent의 클린업 함수가 실행되며 "ChildComponent Unmounted" 메시지가 출력

 


끝 ~

'3주차' 카테고리의 다른 글

[React] Custom Hook  (0) 2024.11.01
[React] useEffect 훅과 의존성 배열  (0) 2024.11.01
[3주차] JSX 알아보기  (0) 2024.10.31
패키지 Manager~ 그게뭘까?  (0) 2024.10.30
리액트가 처음인 당신께...  (3) 2024.10.29