카테고리 없음

React.js - 라이프사이클, useEffect 사용하기, useEffect로 라이프사이클 제어하기

icems0428 2025. 1. 30. 19:11

 라이프사이클이란?

 사람의 생애주기같이, 컴포넌트에도 라이프사이클이 있다. mount, update, unmount 순서로 흘러간다.

출처 : 한 입 크기로 잘라먹는 리액트

  • Mount : 컴포넌트가 처음으로 렌더링 되었을 때
  • Update : 컴포넌트가 리렌더링 되었을 때
  • UnMount : 컴포넌트가 화면에서 사라질 때

useEffect 사용하기

import "./App.css";
import Viewer from "./components/Viewer";
import Controller from "./components/Controller";
import { useState, useEffect } from "react";

function App() {
  const [count, setCount] = useState(0);
  const [input, setInput] = useState("");

  useEffect(() => {
    console.log(`count: ${count} / input: ${input}`);
  }, [count, input]);
  // 의존성 배열
  // dependency array
  // deps

  const onClickButton = (value) => {
    setCount(count + value);
  };

  return (
    <div className="App">
      <h1>Simple Counter</h1>
      <section>
        <input
          value={input}
          onChange={(e) => {
            setInput(e.target.value);
          }}
        />
      </section>
      <section>
        <Viewer count={count} />
      </section>
      <section>
        <Controller onClickButton={onClickButton} />
      </section>
    </div>
  );
}

export default App;

 

 useEffect라는 훅을 이용해서 컴퍼넌트의 사이드 이펙트를 만들거나 제어할 수 있다. 여기서 사이드 이펙트란, 컴포넌트의 동작에 따라 파생되는 여러 효과들을 말한다.

 우리는 count, input의 state 값이 바뀌면 해당 값을 콘솔에 출력하는 사이드 이펙트를 만들려고 한다. useEffect를 리액트에서 임포트 해오고, useEffect(()=>{}, []) 로 선언한다. 두 번째 매개변수인 배열에 들어있는 값이 변하면 첫 번째 매개변수인 화살표 함수가 실행된다. 이 배열을 우리는 의존성 배열, 영어로는 deps 라고 부른다.

 여기서 한 가지 의문점이 들 수 있다. 그냥 setCount 함수 뒤에 콘솔로 변화한 값을 출력하면 될 걸 왜 굳이 useEffect라는 훅을 사용할까? 그 이유는 바로 리액트의 상태 변화 함수는 비동기로 동작하기 때문이다. 여기서 비동기란, 바로 실행되지 않고 뒤늦게 완료되는 것을 말한다. 그렇기 때문에 setCount 함수가 완료되기 전에 콘솔을 출력하면 변화하기 전의 값이 출력된다. 즉 리액트의 state는 비동기로 업데이트가 되기 때문에, 변경된 state 값을 바로 이용하기 위해서는 useEffect를 사용해야 한다.


useEffect로 라이프사이클 제어하기

// App.jsx
import "./App.css";
import Viewer from "./components/Viewer";
import Controller from "./components/Controller";
import Even from "./components/Even";
import { useState, useEffect, useRef } from "react";

function App() {
  const [count, setCount] = useState(0);
  const [input, setInput] = useState("");
  const isMount = useRef(false);

  // 1. 마운트 : 탄생
  useEffect(() => {
    console.log("mount");
  }, []);

  // 2. 업데이트 : 변화, 리렌더링
  useEffect(() => {
    if (!isMount.current) {
      isMount.current = true;
      return;
    }
    console.log("update");
  });

  // 3. 언마운트 : 죽음

  const onClickButton = (value) => {
    setCount(count + value);
  };

  return (
    <div className="App">
      <h1>Simple Counter</h1>
      <section>
        <input
          value={input}
          onChange={(e) => {
            setInput(e.target.value);
          }}
        />
      </section>
      <section>
        <Viewer count={count} />
        {count % 2 === 0 ? <Even /> : null}
      </section>
      <section>
        <Controller onClickButton={onClickButton} />
      </section>
    </div>
  );
}

export default App;
// Even.jsx
import { useEffect } from "react";

const Even = () => {
  useEffect(() => {
    //클린업, 정리함수
    return () => {
      console.log("unmount");
    };
  }, []);
  return <div>짝수입니다</div>;
};

export default Even;

 

 컴포넌트의 사이드 이펙트에는 라이프 사이클 제어 포함되어 있다. 마운트, 업데이트, 언마운트 될 때 각각 useEffect를 어떻게 사용하는지 알아보자. 

  • 마운트 시에는 deps에는 아무 값도 넣어주지 않는다. useEffect는 deps에 있는 값이 변화해야만 실행되기 때문에 처음 mount될 때 단 한 번만 실행된다.
  • 업데이트 시에는 deps를 생략해준다. 그러면 컴포넌트가 리렌더링 될 때마다 알아서 useEffect가 실행된다.
  • 언마운트 시에는 콜백 함수에서 함수를 반환하는 리턴문을 작성해준다. 이 리턴문은 useEffect 함수가 종료될 때, 즉 언마운트 될 때 실행된다.