1. React.memo로 감싼 자식에게 함수를 내려줄 때
const Child = React.memo(({ onClick }: { onClick: () => void }) => {
console.log("Child render");
return <button onClick={onClick}>클릭</button>;
});
function Parent() {
const [count, setCount] = useState(0);
const handleClick = useCallback(() => {
console.log("click");
}, []);
return (
<>
<button onClick={() => setCount(c => c + 1)}>+</button>
<Child onClick={handleClick} />
</>
);
}
useCallback 없으면
→ 부모 리렌더 → 매번 새로운 함수 생성 → Child도 리렌더
useCallback 있으면
→ 함수 참조 유지 → Child 리렌더 방지
2. useEffect / useMemo 의존성으로 “함수”가 들어갈 때
const fetchData = useCallback(() => {
api.get("/data");
}, []);
useEffect(() => {
fetchData();
}, [fetchData]); // 안정적인 참조 필요
❌ useCallback 없으면
→ 렌더마다 함수 변경 → effect 매번 실행
이건 린트 때문에 억지로 쓰는 경우도 많음
(실무에서 제일 흔한 useCallback 사용 이유)
3. 자식 컴포넌트가 렌더 비용이 클 때
<HeavyChart onChange={handleChange} />
함수 재생성은 왜 문제가 아닌가?
이게 렌더마다 다시 만들어지는 비용은:
👉 JS 엔진 기준으로 거의 공짜 수준
반면 React 렌더링에서 진짜 비싼 건:
- 컴포넌트 호출
- reconciliation : 이전 렌더 결과와 새 렌더 결과를 비교해서 실제 DOM을 어떻게 바꿀지 계산하는 과정
- 비싼 건 리렌더 + diff + 자식 트리
👉 함수 재생성 자체는 병목이 아님
그럼 useCallback은 “공짜”냐? ❌
아님. 숨겨진 비용이 있음.
useCallback 내부에서 실제로 하는 일 => useCallback(fn, deps) // ≈ useMemo(() => fn, deps)
즉 매 렌더마다: deps 배열 비교
'WEB개발 > REACT' 카테고리의 다른 글
| pull to refresh (0) | 2026.01.12 |
|---|---|
| react router (navigate) (0) | 2025.12.17 |
| [hook] useEffect (0) | 2025.12.16 |
| [hook] useQuery (0) | 2025.12.12 |
| VITE (0) | 2025.03.17 |