코딩기록

리액트) 훅 useRef, useState, useEffect, useLayoutEffect, useCallback, useMemo 란? 본문

프론트/리액트

리액트) 훅 useRef, useState, useEffect, useLayoutEffect, useCallback, useMemo 란?

뽀짝코딩 2025. 6. 4. 19:32
728x90
const handleClick = useCallback(() => {
  console.log("clicked");
}, []);


const btnRef = useRef<HTMLButtonElement | null>(null);
이 한 줄은 리액트에서 DOM 요소를 직접 참조하기 위한 방법


✅ useRef란?

  • React의 훅 중 하나로, 컴포넌트가 리렌더링되어도 유지되는 값을 저장할 수 있음.
  • 보통 DOM 요소나 타이머 ID, 외부 라이브러리 인스턴스 등을 저장하는 데 쓰임.

✅ 이 코드에서의 의미

const btnRef = useRef<HTMLButtonElement | null>(null);

구성 요소 설명

useRef<...>() ref 객체 생성
HTMLButtonElement ref.current가 버튼 요소를 가리키도록 타입 지정
null 초기값: 아직 버튼이 화면에 나타나지 않았기 때문에 null

즉, 이 코드는

“버튼을 참조할 수 있도록 준비해두는 변수”를 만든 것.


✅ 어떻게 사용되나요?

<button ref={btnRef} ...>

이렇게 쓰면, btnRef.current는 렌더링이 끝난 뒤 실제 버튼 DOM을 가리킴.


✅ 왜 쓰나요?

예를 들어:

  • useClickOutside(btnRef, close, showMenu) 처럼 외부 클릭 감지
  • 버튼에 .focus()나 .click() 같은 DOM 메서드를 직접 호출
  • 외부 라이브러리와 연동 시 요소 참조

 

 

 


useRef, useState, useEffect의 차이


✅ 1. useState: 상태를 저장하고, 변경 시 렌더링

const [count, setCount] = useState(0);
setCount(prev = > prev + 1);
  • 설명: 컴포넌트 내부 상태 저장 및 갱신
  • 렌더링 유발: ✅
  • 사용자 입력, 상태 추적 등에 사용

📌 예시

const [text, setText] = useState('');
<input value={text} onChange={(e) => setText(e.target.value)} />

✅ 2. useRef: 렌더링과 무관하게 값을 저장 (DOM 요소 참조용도도 가능)

const inputRef = useRef<HTMLInputElement | null>(null);
inputRef.current?.focus();
  • 설명: DOM 요소 참조 또는 렌더링과 무관한 값 저장, 변경해도 렌더링이 발생하지 않음
  • 렌더링 유발: ❌
  • 주로 DOM 요소 참조 또는 렌더링 간 유지되어야 하는 값을 저장할 때 사용
  • 값은 .current로 접근

📌 예시

useEffect(() => {
  inputRef.current?.focus();
}, []);

✅ 3. useEffect: 렌더링 이후 실행되는 사이드 이펙트 처리용

useEffect(() => {
  console.log("컴포넌트가 마운트되었어요!");
}, []);
  • 설명: 컴포넌트 렌더 후 실행되는 부수 효과를 실행
  • 렌더링 유발: ❌
  • 주로 API 호출, 이벤트 등록, 타이머, 외부 상태 연동 등에서 사용

📌 예시

useEffect(() => {
  const id = setInterval(() => {
    console.log("1초마다 실행");
  }, 1000);

  return () => clearInterval(id); // cleanup
}, []);

 


✅ 핵심 비교 요약표

항목  useState  useRef  useEffect
상태 저장
렌더링 트리거
DOM 접근 가능
부수 효과 처리
대표 예시 사용자 입력값 DOM 요소, 타이머 ID API 호출, 외부 연동

 

 

✅ useState, useRef, useEffect 정리표               

항목    useState    useRef  useEffect
🔁 렌더링 여부 값이 바뀌면 렌더링 발생 값이 바뀌어도 렌더링 ❌ ❌ 직접 렌더링 안 함 (렌더 후 실행됨)
💾 저장 용도 화면에 영향을 주는 상태 값 저장 렌더와 무관한 값, DOM 참조용 사이드 이펙트 (API 호출, 이벤트 등록 등)
🎯 주요 사용처 입력값, 토글 상태, UI 상태 등 DOM 요소 접근, 타이머 ID 저장, 이전 값 저장 등 초기 렌더, 의존 값 변경 시 실행되는 부가 작업 처리
🧠 기억 방식 const [value, setValue] = useState(...) const ref = useRef(null)ref.current로 접근 useEffect(() => { ... }, [deps])
🛠 대표 기능 값 변경 + 화면 업데이트 참조 유지 + 렌더링 영향 없음 비동기 처리, 구독, 타이머, 외부 연동

 

📌 한 줄 요약

  • useState: 렌더링에 영향을 주는 상태 저장
  • useRef: 렌더링과 상관없는 값 또는 DOM에 접근할 때 사용
  • useEffect: 렌더링 이후 부수 효과 처리 (API 호출 등)

 


 

useCallback, useMemo, useLayoutEffect 까지 포함한 전체 훅


✅ 4. useLayoutEffect

  • 설명: 렌더 직후, 화면 그리기 전에 실행되는 효과
  • 용도: 레이아웃 계산, 스크롤 위치 조정

📌 예시

useLayoutEffect(() => {
  const { height } = ref.current!.getBoundingClientRect();
}, []);

✅ 5. useCallback

  • 설명: 함수를 메모이제이션하여 재생성 방지
  • 렌더링 유발: ❌ (성능 최적화 목적)
📌 예시
const handleClick = useCallback(() => {
  console.log("clicked");
}, []);

✅ 6. useMemo

  • 설명: 연산 결과를 메모이제이션하여 재계산 방지
  • 렌더링 유발: ❌ (성능 최적화 목적)

📌 예시

const expensiveResult = useMemo(() => {
  return calculateHeavy(items);
}, [items]);

 


✅ React 주요 훅 비교 정리표

Hook  주 용도  영향  대표 사용 예시
useState 상태 저장 & 값 변경 시 컴포넌트 리렌더링 ✅ 있음 입력값, 토글, 카운터 등
useRef 렌더링과 관계없는 값을 저장하거나 DOM에 접근할 때 사용 ❌ 없음 input 포커스, 타이머 ID, 이전 값 저장
useEffect 컴포넌트 렌더 후 실행되는 부수 효과 처리 ❌ 없음 API 요청, 이벤트 리스너 등록/해제 등
useLayoutEffect useEffect와 유사하지만 DOM 변경 직후, 페인트 전에 실행됨 ❌ 없음 레이아웃 측정, 스크롤 위치 설정 등
useCallback 함수 자체를 메모이제이션 (의존값이 변하지 않으면 동일 함수 유지) ❌ 없음 자식 컴포넌트에 함수 props 전달 시 불필요한 렌더 방지
useMemo 계산량이 많은 값을 메모이제이션 (의존값이 바뀌지 않으면 재계산 안 함) ❌ 없음 필터링된 배열, 정렬 결과 등 리렌더마다 계산 방지

✅ 상황별 사용 가이드

상황  사용할 훅  이유
버튼 클릭 시 상태 변경하고 다시 렌더링 useState 값 변경과 동시에 UI를 반영해야 하기 때문
DOM 요소에 직접 접근하고 싶음 (예: input 포커스) useRef 렌더와 관계없이 DOM을 직접 참조
컴포넌트 렌더 후 API 요청 등 부수 작업 useEffect 렌더 이후 실행되는 부수 효과 처리
리렌더 직후 DOM 크기 측정, 스크롤 위치 설정 필요 useLayoutEffect 브라우저가 그리기 전에 실행되므로 레이아웃 작업에 적합
자식 컴포넌트에 콜백 함수 전달 시, 함수가 자꾸 새로 생성됨 useCallback 동일 참조 유지로 자식 불필요 렌더링 방지
계산 비용이 큰 배열 필터링 결과 등을 재사용하고 싶음 useMemo 값이 변하지 않으면 계산 결과를 재사용하여 성능 최적화 가능

💡 예시 코드: useCallback과 useMemo

const memoizedCallback = useCallback(() => {
  doSomething(a, b);
}, [a, b]); // a, b가 변할 때만 새로 만듦

const filteredItems = useMemo(() => {
  return items.filter(item => item.active);
}, [items]); // items가 바뀌지 않으면 기존 결과 재사용

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

참고

쳇GPT

 

 

반응형
Comments