091
[JS/React] JSX(4): Lifecycle, Hook 본문
[JS/React] JSX(4): Lifecycle, Hook
공구일 2026. 4. 12. 04:025. Lifecycle(생명주기) & Hook(훅)
- 생명주기(Lifecycle)이란 리액트 컴포넌트가 생성되고 사라지는 전 과정을 의미합니다.

- 훅(Hook)은 함수 컴포넌트에서 React State와 생명주기 기능을 연동할 수 있게 해주는 함수입니다.

-> 훅의 이름은 모두 use로 시작해야하며, 원하는 시점에 함수가 실행되도록 만드는 함수가 훅입니다.
const [변수명, set함수명] = useState(초기값);
const [count, setCount] = useState(0);
• useState(상태관리): 컴포넌트 내에서 변하는 데이터를 관리할 때 사용
-> 상태가 업데이트되면 리액트는 해당 컴포넌트를 다시 렌더링하여 화면에 갱신하며, set 함수가 비동기적으로 동작합니다.
useEffect(이펙트 함수, 의존성 배열);
useEffect(() => { console.log("마운트됨"); }, []);
• useEffect(사이드 이펙트 처리): 서버 데이터 수신, DOM 직접 변경 등 렌더링 이후에 실행되어야하는 작업에 사용
-> API 호출, 타이머 설정, DOM 직접 조작 등 '외부 시스템'과 통신할 때 주로 사용합니다. 이전에 useState의 set함수의 비동기 방식 때문에 console.log(...) 호출에서 이전 값이 나온 것을 이 useEffect와 함께 사용하면 렌더링 완료 후 최신 값을 확인할 수 있습니다.
import {useState,useEffect} from "react";
useEffect(()=>{ console.log(count); },[count]);
-> Counter 컴포넌트에 이렇게 두 줄을 추가하고 나면 최신값으로 console.log가 출력되는 것을 알 수 있습니다.

-> 클래스 컴포넌트에서 제공하는 생명주기 함수인 componentDidMount(), componentDidUpdate(), componentWillUnmount()와 동일한 기능을 하나로 통합해서 제공합니다.
-> 뒷정리(Cleanup) 함수란 useEffect 안에서 return으로 반환하는 함수입니다. 타이머, 이벤트 리스너 등을 해제해 메모리 누수를 방지합니다.


+) 자동 카운터 실습
import { useState, useEffect } from "react";
export default function AutoCounter(props) {
const [count, setCount] = useState(0);
const [isRunning, setIsRunning] = useState(false);
// useEffect(() => {
// let timer;
// if (isRunning) {
// timer = setTimeout(function () {
// setCount(count + 1);
// }, 1000);
// }
// return () => clearTimeout(timer);
// }, [count, isRunning]);
useEffect(() => {
let timer;
if (isRunning) {
timer = setInterval(() => {
setCount(prev=>prev+1);
}, 1000);
}
return () => clearInterval(timer);
}, [isRunning]);
return (
<div>
<p>{count}</p>
<button onClick={() => setIsRunning(!isRunning)}>
{isRunning ? "STOP" : "START"}
</button>
</div>
)
}
-> setInterval(...)과 setTimeout(...): setInterval은 지정된 시간 간격마다 코드를 무한히 반복해서 실행합니다. 그에 반해 setTimeout은 지정된 시간이 지난 후에 코드를 단 한번만 실행하고 종료합니다. 그래서 setTimeout을 쓸 때는 의존성배열에 count를 넣어 변화할 때마다 실행될 수 있게 해줘야합니다. 그리고 setTimeout은 보통의 경우 한번 실행되니까 clearTimeout를 쓰는 것은 특정 상황에서의 선택이지만, setInterval은 쓰면 반드시 clearInterval을 통해 메모리 누수를 방지해야합니다.
-> function(){}과 ()=>{}: 두개는 this 바인딩에서 가장 큰 차이를 가집니다. function(){}은 자기 자신만의 this를 가지지만, 화살표 함수는 this가 없습니다. 이러한 this문제로부터 자유롭기 위해 React에서는 화살표 함수를 사용합니다.
-> setCount(prev=>prev+1): set 함수 안에 값이 아닌 함수가 들어오면 무조건 그 함수의 첫번째 매개변수에 리액트 앤진 내부 메모리가 기억하고 있는 가장 최신 state 값을 꽂아주도록 프로그래밍되어있기 떄문에 prev를 넣어도 count 값 연산이 됩니다.
const memoizedValue = useMemo(() => {
return computeExpensiveValue(a, b);
}, [a,b);
• useMemo(연산 결과 재사용): 비용이 많이 드는 복잡한 계산값을 기억해두었다가 재사용
-> 의존성 배열의 값이 변하지 않으면 이전에 계산한 값을 그대로 반환하여 성능을 최적화합니다. 이러한 성능 최적화 기법을 메모이제이션(Memoization)이라고 합니다.
+) 느리게 작동하는 숫자 제곱 함수
import { useState, useMemo } from 'react';
function BigSquare() {
const [number, setNumber] = useState(0); // 제곱 계산 입력값
const [count, setCount] = useState(0); // “+1”버튼 클릭시 증가값
const slowSquare = (num) => { // 느리게 계산되는 제곱 함수 (예제용으로 일부러 지연)
console.log('계산 중...');
let result = 0;
for (let i = 0; i < 2500000000; i++) {
result = num * num;
}
return result;
};
// useMemo로 계산 결과를 메모이제이션
const squared = useMemo(() => slowSquare(number), [number]);
return (
<div>
<h2>느린 제곱 계산기</h2>
<input
type="number"
value={number}
onChange={(e) => setNumber(Number(e.target.value))}
/>
<p>제곱 결과: {squared}</p>
<p>{count}</p>
<button onClick={() => setCount(count + 1)}>+1</button>
</div>
);
}
export default BigSquare;
-> 느리게 작동하는 제곱함수와 카운터를 동시에 보유하고 있습니다. +1 버튼을 누를 때는 useMemo로 제곱 계산이 수행되지 않아 불필요한 재렌더링 작업이 발생하지않아 지연 시간이 없습니다.
const memoizedCallback = useCallback(() => {
doSomething(a, b);
}, [a, b]);
• useCallback(함수 자체를 재사용): 함수를 메모이제이션하는 훅으로, useMemo가 값을 저장한다면, useCallback은 함수 자체를 저장합니다. 의존성 배열의 값이 바뀔 때만 함수를 새로 만들고 그렇지 않으면 기존 함수를 재사용합니다.
-> useEffect 의존성 배열에 함수를 넣어야할 때는 반드시 useCallback으로 감싸야합니다. 왜냐면 자바스크립트는 객체나 함수는 내용이 완벽이 같아도 새로 만들게 되면 메모리 주소의 차이로 인해 다르게 인식하기 때문에 다시 컴포넌트를 그리는 리렌더링을 할 때 같은 함수(원래의 A와 새로 만들어진 B)가 새로운 메모리 주소에 쓰여져서 A에서 B로 바뀌었다고 생각되어 API 서버 호출을 다시 실행하며 서버가 공격당하게 됩니다.
=> 이때 useCallback을 사용하면, 의존성 배열을 확인 후 키워드의 변경이 없다면 B를 만들지 말고 A를 그대로 재사용하라고 합니다.
+) 검색결과
const fetchData = useCallback(() => {
console.log("데이터 불러오는 중...");
setTimeout(() => {
setData(`”${keyword}”에 대한 검색 결과`);
}, 1000);
}, [keyword]); // keyword가 바뀔 때만 함수 재생성
// keyword 변경 시 자동 호출
useEffect(() => {
console.log("useEffect()");
if (keyword) fetchData();
}, [fetchData]);
-> fetchData() 함수는 useCallback 훅을 통해 함수 참조가 고정되었으며, keyword 변경 시에만 새로운 함수를 생성합니다.
• useRef(DOM 접근 및 값 유지): 렌더링 없이 값을 저장하는 훅으로, 렌더링을 유발하지 않는 변수 저장소이자, DOM 요소에 직접 접근할 때 사용합니다. 브라우저의 DOM을 가르키는 기능과 값을 바꿔도 화면을 다시 안 그리는 두가지의 기능이 메인입니다.
-> useRef을 통해 참조하고 있는 값에 접근하기위해서는 .current를 사용해줘야하는데 그 이유는 항상 { current: 저장값 }의 형태로 useRef가 제공하기 때문입니다.

+) input 태그에 포커싱
import { useState, useRef } from "react";
export default function TextInputWithFocusButton(props) {
const inputElem = useRef(null);
const onButtonClick = () => {
inputElem.current.focus();
}
return (
<div>
<input ref={inputElem}></input>
<button onClick={onButtonClick}>
Focus the input
</button>
</div>
);
}
- 만약에 직접 훅을 만들어서 사용하고 싶다면, 커스텀 훅으로 use를 시작으로 만들어 사용할 수 있습니다.



import { useState } from "react";
function useCounter(initialValue){
const [count, setCount] = useState(initialValue);
const increaseCount = () => setCount((count) => count+1);
const decreaseCount = () => setCount((count) => count-1);
return [count, increaseCount, decreaseCount];
}
export default useCounter;
import { useState, useEffect } from "react";
import useCounter from "../hooks/useCounter";
const MAX_CAPACITY = 10;
function Accomodate(props){
const [isFull, setIsFull] = useState(false);
const [count,increaseCount,decreseCount] = useCounter(0);
useEffect(()=>{
console.log("----------------");
console.log("useEffect()가 호출되었습니다.");
console.log(`isFull: ${isFull}`);
});
useEffect(()=>{
setIsFull(count >= MAX_CAPACITY);
console.log(`현재 인원 수: ${count}명`);
},[count]);
return(
<div>
<h3>총 {count}명 수용했습니다.</h3>
{count < MAX_CAPACITY &&
<button onClick={increaseCount}>입장</button>}
{count > 0 &&
<button onClick={decreseCount}>퇴장</button>}
{isFull && <p style={{color:'red'}}>정원이 꽉찼습니다.</p>}
</div>
)
}
export default Accomodate;
-> JSX 태그는 자바스크립트에서 언제나 true로 취급하기 때문에 반대쪽 조건이 사실이면 반환됩니다.
'Programming Language > JavaScript&TypeScript' 카테고리의 다른 글
| [JS/React] 리스트와 키, 입력 폼 (0) | 2026.04.18 |
|---|---|
| [JS/React] 이벤트 핸들링 & 조건부 렌더링 (0) | 2026.04.12 |
| [JS/React] JSX(3): Component 실습, State (0) | 2026.04.12 |
| [JS/React] JSX(2): Component, Element (1) | 2026.04.10 |
| [JS/React] JSX(1): 개념과 초기 세팅 설명 (1) | 2026.04.09 |
