Notice
Recent Posts
Recent Comments
Link
«   2026/07   »
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
Archives
Today
Total
관리 메뉴

꽃 같은 인생

React 📌6. React 컴포넌트 생명주기, Hooks📝 본문

oz코딩스쿨/React&Redux

React 📌6. React 컴포넌트 생명주기, Hooks📝

flo-jee 2025. 2. 12. 20:05

🎯 React 컴포넌트 생명주기 (Lifecycle) 정리 🎯


1️⃣ 컴포넌트 생명주기란?

React 컴포넌트는 탄생(Mount) → 업데이트(Update) → 소멸(Unmount) 과정을 거칩니다.

클래스형 컴포넌트에서는 생명주기 메서드를, 함수형 컴포넌트에서는 useEffect()를 사용하여 특정 시점에 작업을 수행할 수 있습니다.

컴포넌트 생명주기 주요 과정

  1. 마운트(Mount): 컴포넌트가 처음 생성되어 화면에 나타날 때
  2. 업데이트(Update): 상태(state)나 props가 변경될 때
  3. 언마운트(Unmount): 컴포넌트가 제거될 때

💡 쉽게 말하면?

컴포넌트의 탄생 → 변화 → 죽음 과정을 관리하는 것이 생명주기입니다.


2️⃣ 클래스형 컴포넌트에서의 생명주기

클래스형 컴포넌트에서는 생명주기 메서드를 사용하여 특정 시점에 코드 실행이 가능합니다.

📌 클래스형 생명주기 메서드

생명주기 단계 메서드 역할

마운트 constructor 초기 state 설정, 이벤트 바인딩
componentDidMount 컴포넌트가 화면에 나타난 후 실행 (API 호출 등)
업데이트 shouldComponentUpdate 리렌더링 여부 결정 (true면 렌더링)
componentDidUpdate state, props가 변경된 후 실행 (데이터 요청, DOM 조작 등)
언마운트 componentWillUnmount 컴포넌트가 제거되기 직전에 실행 (클린업 작업)

클래스형 컴포넌트 생명주기 예제

import React, { Component } from "react";

class LifecycleDemo extends Component {
    constructor(props) {
        super(props);
        this.state = { count: 0 };
        console.log("1️⃣ constructor - 초기화");
    }

    componentDidMount() {
        console.log("2️⃣ componentDidMount - 마운트 완료");
    }

    shouldComponentUpdate(nextProps, nextState) {
        console.log("3️⃣ shouldComponentUpdate - 리렌더링 여부 결정");
        return true; // false를 반환하면 업데이트되지 않음
    }

    componentDidUpdate(prevProps, prevState) {
        console.log("4️⃣ componentDidUpdate - 업데이트 완료");
    }

    componentWillUnmount() {
        console.log("5️⃣ componentWillUnmount - 언마운트");
    }

    render() {
        console.log("🔄 render - 화면 렌더링");
        return (
            <div>
                <h1>Count: {this.state.count}</h1>
                <button onClick={() => this.setState({ count: this.state.count + 1 })}>
                    Increment
                </button>
            </div>
        );
    }
}

export default LifecycleDemo;

📌 실행 흐름 1️⃣ constructor() → 2️⃣ render() → 3️⃣ componentDidMount() (최초 마운트)

4️⃣ 버튼 클릭 → 5️⃣ shouldComponentUpdate() → 6️⃣ render() → 7️⃣ componentDidUpdate()

📌 언마운트 시

  • componentWillUnmount()가 실행됨 (이벤트 리스너 제거, API 요청 취소 등 클린업 작업 수행)

3️⃣ 함수형 컴포넌트에서의 생명주기 (useEffect)

함수형 컴포넌트에서는 useEffect() 훅을 사용하여 생명주기 이벤트를 처리합니다.

useEffect 기본 문법

useEffect(() => {
    // 실행할 코드
    return () => {
        // 클린업 (언마운트 시 실행)
    };
}, [의존성 배열]);

생명주기 클래스형 메서드 함수형 useEffect()

마운트 componentDidMount useEffect(() => {...}, [])
업데이트 componentDidUpdate useEffect(() => {...}, [변수])
언마운트 componentWillUnmount useEffect(() => {... return () => {...}}, [])

1. 마운트 시 (componentDidMount)

import React, { useEffect } from "react";

function Component() {
    useEffect(() => {
        console.log("✅ 마운트 완료 (한 번만 실행)");

        return () => {
            console.log("🛑 언마운트 (클린업)");
        };
    }, []); // 빈 배열([])을 넣으면 마운트 시 한 번만 실행됨

    return <h1>Hello, React!</h1>;
}

📌 설명

  • useEffect(() => {...}, []) → 최초 마운트 시 한 번만 실행
  • return () => {...} → 언마운트 시 실행되는 클린업 함수

2. 업데이트 시 (componentDidUpdate)

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

function Counter() {
    const [count, setCount] = useState(0);

    useEffect(() => {
        console.log(`✅ 카운트 변경됨: ${count}`);
    }, [count]); // count가 변경될 때마다 실행됨

    return (
        <div>
            <h1>Count: {count}</h1>
            <button onClick={() => setCount(count + 1)}>Increment</button>
        </div>
    );
}

📌 설명

  • useEffect(() => {...}, [count]) → count가 변경될 때마다 실행됨

3. 언마운트 시 (componentWillUnmount)

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

function Timer() {
    useEffect(() => {
        const interval = setInterval(() => {
            console.log("⏳ 1초마다 실행 중...");
        }, 1000);

        return () => {
            console.log("🛑 언마운트 - 타이머 정리");
            clearInterval(interval);
        };
    }, []);

    return <h1>타이머 실행 중...</h1>;
}

📌 설명

  • return () => {...} 부분에서 타이머를 정리하여 메모리 누수를 방지

  • 🎯 React 컴포넌트 생명주기 최종 정리생명주기 클래스형 (Component) 함수형 (useEffect())
    마운트 componentDidMount() useEffect(() => {...}, [])
    업데이트 componentDidUpdate() useEffect(() => {...}, [의존성])
    언마운트 componentWillUnmount() useEffect(() => {... return () => {...}}, [])

  • 🎯 언제 useEffect()를 사용해야 할까?이벤트 리스너 추가/제거 (componentDidMount & componentWillUnmount)✅ state 변경 감지 (componentDidUpdate)
  • 타이머 설정 & 클리어 (componentWillUnmount)
  • API 데이터 요청 (componentDidMount)

🔥 React Hooks - useEffect 완벽 정리 🚀


1. useEffect란?

📌 React 컴포넌트가 렌더링될 때 특정 작업(부수 효과, Side Effect)을 수행하는 Hook

📌 예: 데이터 가져오기, DOM 조작, 구독(subscribe), 타이머 설정 등

📌 클래스 컴포넌트의 componentDidMount, componentDidUpdate, componentWillUnmount를 대체

✔ useEffect 기본 구조:

import { useEffect } from "react";

useEffect(() => {
  // 실행할 코드 (예: 데이터 가져오기)
});

2. useEffect 실행 시점

useEffect의 동작 방식은 **의존성 배열(dependency array)**에 따라 달라짐!

1️⃣ 렌더링마다 실행 (useEffect(() => {...}))

📌 컴포넌트가 렌더링될 때마다 실행 (초기 렌더링 + 업데이트 시)

📌 의존성 배열 []을 생략하면, 모든 렌더링마다 실행됨

useEffect(() => {
  console.log("매번 렌더링될 때 실행!");
});

사용 예시: 로그 출력, DOM 조작 등


2️⃣ 처음 마운트될 때 한 번만 실행 (useEffect(() => {...}, []))

📌 컴포넌트가 처음 렌더링될 때만 실행 (업데이트 시 실행 X)

📌 의존성 배열을 빈 배열 []로 설정하면, 한 번만 실행됨!

useEffect(() => {
  console.log("처음 한 번 실행!");
}, []);

사용 예시: API 데이터 가져오기 (fetch), 이벤트 리스너 등록


3️⃣ 특정 값이 변경될 때 실행 (useEffect(() => {...}, [의존성]))

📌 의존성 배열에 있는 값이 변경될 때만 실행

useEffect(() => {
  console.log(`count 값이 변경됨: ${count}`);
}, [count]);

사용 예시: 특정 상태(state)가 변경될 때 실행 (예: 입력 값 감지, 필터 적용 등)


📌 (4) 클린업 함수 (컴포넌트 언마운트 시 실행)

📌 컴포넌트가 제거될 때(언마운트) 실행되는 정리(clean-up) 코드 추가 가능

📌 return 안에서 정리할 코드를 작성

useEffect(() => {
  console.log("컴포넌트가 마운트됨!");

  return () => {
    console.log("컴포넌트가 언마운트됨! (정리)");
  };
}, []);

사용 예시: 이벤트 리스너 제거, 타이머 제거, API 요청 취소


3. useEffect 예제 코드

1️⃣ useEffect로 API 데이터 가져오기 (fetch)

import { useEffect, useState } from "react";

function App() {
  const [data, setData] = useState(null);

  useEffect(() => {
    fetch("<https://jsonplaceholder.typicode.com/posts/1>")
      .then((res) => res.json())
      .then((json) => setData(json));
  }, []);

  return
{data ? data.title : "Loading..."}
;
}

export default App;

✔ useEffect를 사용하여 컴포넌트가 처음 마운트될 때 API 요청을 수행

✔ 빈 배열 []을 넣어 한 번만 실행됨


2️⃣ useEffect로 타이머 설정 & 정리하기

import { useEffect, useState } from "react";

function Timer() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    const interval = setInterval(() => {
      setCount((prev) => prev + 1);
    }, 1000);

    return () => {
      clearInterval(interval); // 정리(clean-up)
    };
  }, []);

  return <h1>{count}초</h1>;
}

export default Timer;

✔ setInterval로 매초 count 증가

✔ **클린업 함수(clearInterval)**를 사용하여 컴포넌트가 제거될 때 타이머 정리


  • 🚀 결론: useEffect는 언제 사용할까?이벤트 리스너 추가/제거 (window.addEventListener)애니메이션, 외부 라이브러리 실행
  • 컴포넌트가 언마운트될 때 정리(clean-up) 필요할 때
  • 타이머(setTimeout, setInterval) 관리
  • API 데이터 가져오기 (fetch, axios)
  • 🎯 useEffect 핵심 정리실행 조건 코드 실행 시점
    모든 렌더링마다 실행 useEffect(() => {...}) 초기 렌더링 + 업데이트될 때마다
    한 번만 실행 useEffect(() => {...}, []) 초기 렌더링 시 1회만 실행
    특정 값이 변경될 때 실행 useEffect(() => {...}, [state]) state 값이 바뀔 때 실행
    언마운트 시 실행 (정리) return () => {...} 컴포넌트가 제거될 때 실행

🔥 React 생명주기 함수의 필요성 🚀


1. 생명주기(Lifecycle)란?

📌 React 컴포넌트는 마운트(Mount), 업데이트(Update), 언마운트(Unmount) 단계를 거치면서 동작

📌 특정 시점마다 실행할 코드를 작성할 수 있도록 **생명주기 함수(lifecycle methods)**가 필요


2. 왜 생명주기 함수가 필요할까?

📌 (1) 컴포넌트의 특정 시점에 원하는 동작을 수행하기 위해!

✔ React 컴포넌트는 렌더링될 때 여러 단계를 거침

✔ 특정 단계에서 API 호출, DOM 조작, 이벤트 등록/해제, 상태 변경 등의 작업을 해야 함

✔ 생명주기 함수가 없으면, 언제 실행해야 하는지 알기 어려움

🔹 예제: API 요청은 언제 실행할까?

jsx
복사편집
useEffect(() => {
  fetch("<https://api.example.com/data>")
    .then((res) => res.json())
    .then((data) => setData(data));
}, []); // ✅ 컴포넌트가 처음 렌더링될 때 한 번만 실행

✔ API 요청은 컴포넌트가 마운트될 때 실행해야 함 (useEffect 사용)


📌 (2) 불필요한 코드 실행을 막기 위해!

✔ 모든 렌더링마다 API 요청을 하면 불필요한 네트워크 사용 발생

✔ 특정 상태가 변경될 때만 실행되도록 제어 가능

🔹 예제: 특정 값이 바뀔 때만 실행

jsx
복사편집
useEffect(() => {
  console.log(`count 값이 변경됨: ${count}`);
}, [count]); // ✅ count가 변경될 때만 실행

✔ count가 변경될 때만 실행되어 불필요한 코드 실행을 막음


📌 (3) 메모리 누수를 방지하기 위해!

✔ 이벤트 리스너, 타이머(setInterval), API 요청 등은 컴포넌트가 제거될 때 정리해야 함

✔ 그렇지 않으면 메모리 누수(memory leak) 발생 가능

🔹 예제: 컴포넌트가 제거될 때 타이머 정리

jsx
복사편집
useEffect(() => {
  const interval = setInterval(() => {
    console.log("타이머 실행 중!");
  }, 1000);

  return () => {
    clearInterval(interval); // ✅ 언마운트될 때 정리
  };
}, []);

✔ 클린업 함수(return () => {})를 사용하여 타이머를 정리하지 않으면, 메모리 낭비 발생!


3. React 생명주기 함수 & Hook 비교

📌 React의 생명주기 함수는 클래스 컴포넌트에서 사용되었지만,

📌 현재는 **함수형 컴포넌트 + Hooks (useEffect)**로 대체됨! 🚀

생명주기 단계 클래스 컴포넌트 (예전 방식) 함수형 컴포넌트 (현재 방식)

마운트(Mount) componentDidMount() useEffect(() => {...}, [])
업데이트(Update) componentDidUpdate() useEffect(() => {...}, [의존성])
언마운트(Unmount) componentWillUnmount() useEffect(() => { return () => {...} }, [])

React에서는 useEffect를 사용하여 생명주기를 관리하는 것이 일반적!


4. 생명주기 함수가 없으면 어떤 문제가 생길까?

🚨 문제 1: 비효율적인 렌더링 발생

❌ 불필요한 API 요청이 반복적으로 발생할 수 있음

❌ 불필요한 이벤트 리스너 등록으로 메모리 낭비 발생

🚨 문제 2: 메모리 누수 발생 가능

❌ setInterval, setTimeout을 정리하지 않으면, 컴포넌트가 제거된 후에도 실행됨

❌ 이벤트 리스너(addEventListener)를 해제하지 않으면 불필요한 이벤트 계속 발생

🚨 문제 3: 코드 유지보수가 어려워짐

❌ 컴포넌트가 언제 실행되는지 예측하기 어려움

❌ 특정 동작이 언제 실행되는지 명확하지 않으면, 디버깅이 어려움


  • 🎯 결론: React 생명주기 함수는 필수!불필요한 렌더링을 막아 성능 최적화 가능useEffect를 활용해 생명주기 제어 가능 🚀
  • 메모리 누수 방지를 위한 정리 작업 수행 가능
  • 컴포넌트의 특정 시점에 필요한 작업 수행 가능 (예: API 요청, 이벤트 등록)

🔥 React Hooks - useRef 완벽 정리 🚀


1. useRef란?

📌 useRef는 React에서 DOM 요소에 직접 접근하거나, 값이 변경되어도 렌더링을 발생시키지 않는 변수를 저장하는 Hook이야!

📌 주요 기능:

  1. DOM 요소 직접 접근 → document.getElementById 없이 React에서 DOM 요소 제어 가능
  2. 렌더링 없이 값 유지 → state처럼 값 저장 가능하지만, 변경되어도 컴포넌트가 다시 렌더링되지 않음

✔ useRef 기본 구조:

jsx
복사편집
import { useRef } from "react";

const myRef = useRef(초기값);


2. useRef의 주요 사용 예시

1️⃣ DOM 요소에 접근하기 (포커스 설정, 값 가져오기)

✔ useRef를 사용하면 HTML 요소를 직접 조작 가능

jsx
복사편집
import { useRef } from "react";

function InputFocus() {
  const inputRef = useRef(null); // 초기값: null

  const handleFocus = () => {
    inputRef.current.focus(); // ✅ input 요소에 포커스 설정
  };

  return (
    <div>
      <input ref={inputRef} type="text" placeholder="여기에 입력하세요" />
      <button onClick={handleFocus}>포커스 이동</button>
    </div>
  );
}

export default InputFocus;

버튼 클릭 시, input에 자동으로 포커스 이동!

✔ ref={inputRef}를 설정하면 inputRef.current가 해당 DOM 요소를 가리킴


2️⃣ 값 저장 (렌더링 없이 상태 유지하기)

📌 useRef는 값이 변경되어도 렌더링되지 않음!

📌 State와 달리 useRef 값 변경 시 컴포넌트가 다시 렌더링되지 않음!

jsx
복사편집
import { useRef, useState } from "react";

function Counter() {
  const countRef = useRef(0);
  const [renderCount, setRenderCount] = useState(0);

  const increaseRef = () => {
    countRef.current += 1; // ✅ 값은 변경되지만 렌더링되지 않음
    console.log(`useRef 값: ${countRef.current}`);
  };

  const triggerRender = () => {
    setRenderCount(renderCount + 1); // ✅ 강제로 렌더링 (useState)
  };

  return (
    <div>
      <p>useRef 값: {countRef.current}</p>
      <button onClick={increaseRef}>useRef 값 증가</button>
      <button onClick={triggerRender}>강제 렌더링</button>
    </div>
  );
}

export default Counter;

✔ countRef.current 값이 변경되지만 화면에는 변하지 않음

useState는 값이 변경되면 리렌더링되지만, useRef는 그렇지 않음

렌더링되지 않고 값만 유지하고 싶을 때 유용!


3️⃣ 이전 값 저장하기 (useRef + useEffect)

📌 현재 값과 이전 값을 비교하고 싶을 때 useRef를 활용할 수 있음!

jsx
복사편집
import { useEffect, useRef, useState } from "react";

function PrevValueTracker() {
  const [count, setCount] = useState(0);
  const prevCountRef = useRef(count); // 이전 값 저장

  useEffect(() => {
    prevCountRef.current = count; // ✅ count 변경 시 이전 값 저장
  }, [count]);

  return (
    <div>
      <p>현재 값: {count}</p>
      <p>이전 값: {prevCountRef.current}</p>
      <button onClick={() => setCount(count + 1)}>증가</button>
    </div>
  );
}

export default PrevValueTracker;

✔ prevCountRef.current에 이전 상태 값을 저장

✔ useState 값이 변경될 때마다 이전 값을 기억할 수 있음


3. useRef vs useState 차이점

Hook 값 변경 시 렌더링 여부 주요 사용 목적

useRef ❌ 렌더링되지 않음 값 유지, DOM 접근
useState ✅ 렌더링 발생 상태(state) 관리

 


  • ✨ useRef의 핵심 요약렌더링 없이 값 저장 가능 (countRef.current += 1)✔ State 변경 없이 값만 저장할 때 사용! 🚀
  • 이전 값 저장 및 비교 (prevValue.current)
  • DOM 요소 직접 접근 (inputRef.current.focus())

🔥 React Custom Hooks 완벽 정리 🚀


1. Custom Hook이란?

📌 React에서 useState, useEffect 같은 Hook을 직접 만들어 사용하는 기능!

📌 반복되는 로직을 재사용 가능하게 만들어 코드가 깔끔하고 유지보수하기 쉬워짐

📌 use로 시작하는 JavaScript 함수 → React의 규칙을 따르는 훅

Custom Hook 기본 구조:

import { useState, useEffect } from "react";

function useCustomHook() {
  const [value, setValue] = useState(null);

  useEffect(() => {
    console.log("Custom Hook 동작!");
  }, []);

  return value;
}

export default useCustomHook;

2. Custom Hook을 사용하는 이유

반복되는 로직을 재사용 가능하게 함

컴포넌트의 로직을 분리하여 코드 가독성 향상

useState, useEffect 등 내장 훅과 조합 가능

컴포넌트가 간결해지고 유지보수가 쉬워짐


3. Custom Hook 예제 코드

1️⃣ useFetch - API 데이터 가져오기

📌 반복적으로 사용하는 fetch 요청을 Custom Hook으로 만들기!

import { useState, useEffect } from "react";

function useFetch(url) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await fetch(url);
        if (!response.ok) throw new Error("데이터 불러오기 실패!");
        const result = await response.json();
        setData(result);
      } catch (err) {
        setError(err.message);
      } finally {
        setLoading(false);
      }
    };

    fetchData();
  }, [url]);

  return { data, loading, error };
}

export default useFetch;

API 데이터를 가져오는 fetch 로직을 Custom Hook으로 분리

이제 어디서든 useFetch("API_URL")을 호출하여 사용 가능

📌 사용 예시:

import useFetch from "./useFetch";

function App() {
  const { data, loading, error } = useFetch("<https://jsonplaceholder.typicode.com/posts/1>");

  if (loading) return

로딩 중...

;
  if (error) return

에러: {error}

;

  return

{data.title}

;
}

export default App;

2️⃣ useInput - 입력값 관리

📌 입력 필드(input)의 값을 쉽게 관리하는 Custom Hook 만들기

import { useState } from "react";

function useInput(initialValue) {
  const [value, setValue] = useState(initialValue);

  const handleChange = (e) => {
    setValue(e.target.value);
  };

  return [value, handleChange];
}

export default useInput;

입력값(value)과 변경 함수(handleChange)를 반환

이제 useInput()을 사용하면 쉽게 입력 필드를 관리 가능

📌 사용 예시:

import useInput from "./useInput";

function App() {
  const [name, setName] = useInput("");

  return (
    <div>
      <input type="text" value={name} onChange={setName} placeholder="이름 입력" />
      <p>입력한 이름: {name}</p>
    </div>
  );
}

export default App;

3️⃣ useToggle - 토글 상태 관리

📌 Boolean 값을 쉽게 전환하는 Custom Hook 만들기!

import { useState } from "react";

function useToggle(initialValue = false) {
  const [state, setState] = useState(initialValue);

  const toggle = () => {
    setState((prev) => !prev);
  };

  return [state, toggle];
}

export default useToggle;

상태 값과 토글 함수(toggle)를 반환

이제 useToggle()을 사용하면 간단하게 ON/OFF 상태 관리 가능

📌 사용 예시:

import useToggle from "./useToggle";

function App() {
  const [isVisible, toggleVisibility] = useToggle();

  return (
    <div>
      <button onClick={toggleVisibility}>
        {isVisible ? "숨기기" : "보이기"}
      </button>
      {isVisible && <p>이 텍스트가 보입니다!</p>}
    </div>
  );
}

export default App;

4. Custom Hook을 만들 때 주의할 점

📌 반드시 use로 시작해야 함 (useFetch, useInput 등)

📌 다른 Hook(useState, useEffect 등)과 함께 사용 가능

📌 컴포넌트 내부가 아니라 최상위에서 정의해야 함


  • 🎯 Custom Hook 핵심 요약useFetch, useInput, useToggle 같은 유용한 Custom Hook 제작 가능컴포넌트를 더 간결하게 만들고 유지보수를 쉽게 해줌 🚀
  • useState, useEffect와 조합하여 다양한 기능 추가 가능
  • 반복되는 로직을 재사용할 수 있도록 만듦