Language/React.js

[React] 라이프 사이클

JJcoding 2024. 10. 17. 15:53

Mount

  • 탄생. 컴포넌트가 탄생하는 순간
  • 화면에 처음 렌더링 되는 순간
  • “A 컴포넌트가 Mount 되었다.” = A 컴포넌트가 화면에 렌더링 되었다.
  • 서버에서 데이터를 불러오는 작업 등을 할 수 있다.

Update

  • 변화. 컴포넌트가 다시 렌더링 되는 순간
  • 리렌더링 될 때를 의미
  • “A 컴포넌트가 업데이트 되었다.” = A 컴포넌트가 리렌더링 되었다.
  • 어떤 값이 변경되었는지 콘솔에 출력 등을 할 수 있다.

UnMount

  • 죽음. 컴포넌트가 화면에서 사라지는 순간
  • 렌더링에서 제외되는 순간을 의미
  • “A 컴포넌트가 언마운트 되었다.” = A 컴포넌트가 화면에서 사라졌다.
  • 컴포넌트가 사용하던 메모리 정리 등을 할 수 있다.
  • 라이프사이클 단계 별로 컴포넌트들이 각각 다른 작업을 수행하도록 만드는 것을 라이프사이클 제어라고 한다.

useEffect

  • 리액트 컴포넌트의 사이드 이펙트를 제어하는 새로운 React Hook
  • 사이드 이펙트 : 리액트에서는 부수적인 효과, 파생되는 효과로 해석하면 된다.

 

App.jsx

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

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;

  • 배열(deps) 안에 들어있는 값이 변하면, 앞에 콜백 함수가 호출되는 방식이다.
  • 그렇다면 onClickButton 함수가 실행될 때 console.log를 찍으면 똑같이 동작하는 것이 아닌가?
  const onClickButton = (value) => {
    setCount(count + value);
    console.log(count);
  };
  • 결과는 아니다. 왜냐하면 state는 비동기 방식으로 동작하기 때문이다. 따라서 콘솔에 나온 결과값은 함수가 실행되기 전에 값으로 출력이 된다.
  • 따라서 state가 변경되었을 때 어떤 변화를 살펴보고 싶다면 useEffect 훅을 사용해야 한다.

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

 

App.jsx

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

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;
  • deps에 빈 배열을 넣으면 mount 될 때만 useEffect 함수가 실행된다.
  • deps에 아무것도 넣지 않으면 mount 될 때, update 될 때 모두 useEffect 함수가 실행된다.
  • 만약 update가 될 때만 함수가 실행되게 하고 싶다면 위처럼 useRef 함수를 활용할 수 있다.
  • unmount 실습을 위해 나타났다 사라졌다 하는 컴포넌트를 생성한다.

 

Even.jsx

import { useEffect } from "react";

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

export default Even;
  • 정리함수(useEffect 안에 있는 return 함수)는 useEffect가 끝날 때 실행이 된다.

 

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