반응형
useCallback
**함수의 메모이제이션(기억)**을 위한 훅입니다.
컴포넌트가 리렌더링될 때마다 새로 정의되는 함수를 같은 참조로 유지하고 싶을 때 사용합니다.
tsx
const increment = useCallback(() => { setCount((prev) => prev + 1); }, []);
- useCallback(fn, deps)는 deps 배열이 바뀌지 않는 한 fn 함수를 재생성하지 않음
- 주로 props로 함수를 자식 컴포넌트에 넘길 때, 불필요한 리렌더링 방지에 유용
📌 1. useCallback과 useMemo의 차이
useCallback과 useMemo는 뭐가 다른가요?
항목 useCallback useMemo
| 목적 | 함수를 메모이제이션 | 값을 메모이제이션 |
| 반환 값 | 함수 | 계산된 값 |
| 사용 예시 | 이벤트 핸들러, prop으로 함수 전달 시 | 연산 비용 큰 값 계산, 의존성 관리 |
tsx
const memoizedCallback = useCallback(() => { doSomething(a, b); }, [a, b]);
const memoizedValue = useMemo(() => { return computeExpensiveValue(a, b); }, [a, b]);
전략 설명
| 기본적으로는 useMemo, useCallback 없이 작성 | |
| 성능 이슈가 실제로 발생할 때만 도입 | |
| props로 넘기는 함수가 자주 리렌더링되고, React.memo 자식 컴포넌트가 있는 경우에 useCallback | |
| 계산량이 많은 함수 결과가 렌더링마다 재계산되는 경우에만 useMemo |
📌 2. 불필요하게 사용되는 경우와 주의점
언제 useCallback이나 useMemo를 불필요하게 쓰는 경우가 있나요?
- 불필요한 메모이제이션은 성능을 오히려 떨어뜨릴 수 있음
- 리렌더링이 거의 없거나, 함수가 가벼운 경우 굳이 useCallback 쓸 필요 없음
- 주의할 점:
- 너무 많은 의존성을 가진 경우 ⇒ 오히려 자주 재생성됨
- 메모이제이션한 값을 사용하는 곳이 없다면 의미 없음
✅ 언제 쓰는 게 좋을까?
- prop으로 함수를 자식 컴포넌트에 전달할 때
- 함수/값이 렌더링 시 계속 새로 생성돼 불필요한 렌더링이 일어날 때
728x90
📌 3. useEffect와 useCallback의 차이
useEffect랑 useCallback이 어떻게 다른가요?
항목 useEffect useCallback
| 역할 | 사이드 이펙트 처리 | 함수 참조 유지 (메모이제이션) |
| 실행 시점 | 렌더링 후 실행 | 렌더링 중 함수 참조 생성 |
| 반환 값 | 정리(cleanup) 함수 | 콜백 함수 |
상황 사용 훅
| API 호출, 이벤트 등록, 외부 라이브러리 호출 등 부수효과 | useEffect |
| 같은 함수 참조가 필요한 경우 (ex. 자식 컴포넌트에 전달) | useCallback |
항목 useEffect useCallback
| 목적 | 부수효과(side effect) 실행 | 콜백 함수의 메모이제이션 |
| 언제 실행? | 컴포넌트 렌더링 후 (렌더 후 발생하는 효과) | 함수가 필요할 때 (렌더 중 함수 정의 시) |
| 무엇을 반환? | 없음 (undefined) | 메모이제이션된 함수 |
| 사용 예 | API 호출, DOM 조작, 타이머 설정 등 | 이벤트 핸들러, 자식 컴포넌트에 props로 전달하는 함수 |
예시:
tsx
useEffect(() => { console.log("데이터 로드"); }, [id]); // id 변경 시 실행됨
const handleClick = useCallback(() => { console.log("버튼 클릭"); }, []);
🟡 useEffect
"렌더링 후 특정 작업을 실행"
→ 사이드 이펙트(Effect), 의존성 배열을 통해 재실행 조건 제어
tsx
useEffect(() => {
console.log("컴포넌트가 마운트되거나 count가 바뀔 때 실행됨");
return () => { console.log("cleanup 함수 (언마운트 또는 업데이트 직전 실행)");
};
}, [count]);
- AJAX 요청, addEventListener, 타이머 등 수행
- return 값으로 cleanup 함수 작성 가능
🟢 useCallback
"함수의 참조를 유지하기 위해 메모이제이션"
→ 함수가 불필요하게 새로 만들어지는 걸 방지
tsx
const handleClick = useCallback(() => { console.log("클릭됨"); }, []);
- 렌더링마다 함수 새로 생성 방지
- 자식 컴포넌트에 props로 넘길 때 유용
- 내부에서 사용하는 상태/props는 의존성 배열에 꼭 포함
📌 4. onSubmit에 useCallback을 사용하는 이유
onSubmit 같은 핸들러에 useCallback을 꼭 써야 하나요?
- 필수는 아니지만, 다음과 같은 경우에 사용이 매우 유용함:
✅ 이유
- 불필요한 재렌더링 방지
- onSubmit을 props로 자식에게 넘기면, 매 렌더링마다 새 함수 생성 시 자식 컴포넌트도 재렌더링됨
- 의존성 명시적 관리
- useCallback(() => { ... }, [deps])처럼 의존성을 정리하면, 내부에서 참조하는 값이 변경될 때만 콜백이 갱신됨
🔍 예시
tsx
const onSubmit = useCallback((e) => { e.preventDefault(); // form 처리 }, [toggleModal]);
이렇게 하면 toggleModal이 변경되지 않는 한 onSubmit은 한 번 생성된 함수 참조를 계속 유지합니다.
+++++++++++
- onSubmit을 자식 컴포넌트에 넘긴다면
- 또는 폼 라이브러리와 함께 쓰고 있다면
👉 useCallback으로 감싸는 것이 안정성과 성능 면에서 좋습니다.
728x90
반응형
'React' 카테고리의 다른 글
| useEffect vs useLayoutEffect (0) | 2025.06.05 |
|---|---|
| useRef (0) | 2025.06.04 |
| GSAP (0) | 2025.05.23 |
| 리액트 비디오 (0) | 2025.05.20 |
| react에서 swiper 사용하기 (0) | 2025.05.20 |