[React] 자식 컴포넌트 렌더링 : 일반 함수 vs useCallback

2025. 5. 2. 11:00·Library & Runtime/React

 

컴포넌트에서 자식에게 함수를 props로 넘길 때, 그 함수가 일반 함수인지 useCallback으로 감싼 함수인지에 따라 자식 컴포넌트의 렌더링 여부가 달라진다.

 

🎯 실험 목표

부모 컴포넌트에서 자식에게 함수를 전달할 때, 일반 함수를 전달했을 때와 useCallback으로 메모이제이션한 함수를 전달했을 때를 비교하고자 예제 코드를 준비했다.

어떤 경우에 자식 컴포넌트가 불필요하게 렌더링되는지 확인해 보자.

 

🧩 예제 코드

ChildRaw: 일반 함수를 props로 받는 자식
ChildMemo: useCallback 함수를 props로 받는 자식

👉 두 자식 모두 React.memo로 감싸져 있음

import { memo, useCallback, useState } from 'react';

const ChildRaw = memo(({ onClick }: { onClick: () => void }) => {
  console.log('🧒 [Raw] 자식 렌더링');
  return <button onClick={onClick}>자식 (일반 함수)</button>;
});

const ChildMemo = memo(({ onClick }: { onClick: () => void }) => {
  console.log('🧒 [Memo] 자식 렌더링');
  return <button onClick={onClick}>자식 (useCallback)</button>;
});

// 부모 컴포넌트에서 자식 컴포넌트로 함수를 넘길 때, useCallback을 쓰는 것과 그냥 함수를 넘기는 것의 차이
// 리렌더링에 어떤 영향을 주는지 확인
const Compare = () => {
  const [count, setCount] = useState(0);
  const [text, setText] = useState('');

  // ❌ 매번 새로 만들어지는 함수 (렌더링마다 변경됨)
  const handleClickRaw = () => {
    console.log('❌ 일반 함수 호출');
  };

  // ✅ useCallback으로 메모이제이션된 함수
  const handleClickMemo = useCallback(() => {
    console.log('✅ useCallback 함수 호출');
  }, []);

  return (
    <div style={{ padding: 20 }}>
      <h2>useCallback 비교 실험</h2>
      <input
        value={text}
        onChange={e => setText(e.target.value)}
        placeholder="입력 시 부모 리렌더링"
      />
      <p>Count: {count}</p>
      <button onClick={() => setCount(c => c + 1)}>부모 카운트 증가</button>

      <h3>자식에 일반 함수 전달</h3>
      <ChildRaw onClick={handleClickRaw} />

      <h3>자식에 useCallback 함수 전달</h3>
      <ChildMemo onClick={handleClickMemo} />
    </div>
  );
};

export default Compare;

 

🔄 실험 결과

✅ 일반 함수 전달 (handleClickRaw)

  • 부모가 리렌더링될 때마다 handleClickRaw 함수가 새로 생성됨
  • ChildRaw는 memo로 감싸져 있어도 props가 변경되므로 리렌더링 발생

 

✅ useCallback 함수 전달 (handleClickMemo)

  • useCallback([]) 덕분에 함수 참조가 변하지 않음
  • ChildMemo는 props가 같다고 판단되어 리렌더링되지 않음

 

📌 실제로 input에 텍스트를 입력하면

  • ChildRaw는 글자마다 계속 렌더링됨
  • ChildMemo는 렌더링되지 않음

 


 

💡 왜 이런 차이가 생길까?

React는 props로 전달된 값이 이전과 같다면 자식 컴포넌트를 리렌더링하지 않는다.
하지만 함수는 JS 객체이기 때문에 렌더링마다 새로 생성되면 참조값이 달라진다.

React는 props가 바뀌었는지 비교할 때 참조(주소)를 비교하기 때문에 렌더링마다 새로 만들어지는 함수는 항상 다른 값으로 간주된다.

 

const fn1 = () => {};
const fn2 = () => {};
console.log(fn1 === fn2); // false!

 

따라서 부모가 리렌더링될 때마다 새 함수를 만들면 자식은 항상 props가 바뀌었다고 판단해 렌더링된다.

 


 

✨ useCallback이 해결해 주는 것

useCallback(fn, [])을 사용하면, 함수 참조를 기억(memoize)해서 렌더링이 다시 일어나도 이전 함수 객체를 재사용한다.
즉, 자식 입장에서는 props가 변하지 않았다고 인식해서 렌더링을 건너뛴다.

 

⚠️ useCallback을 무조건 써야 할까?

무조건 useCallback을 쓰면 오히려 성능이 안 좋아질 수도 있다.
함수를 기억하기 위한 내부 메모이제이션 처리도 비용이 있기 때문이다.

대부분은 일반 함수로 충분하고, 리렌더링을 최적화하려는 특정 조건이 있을 때만 useCallback을 쓴다.

 

✔️ useCallback이 필요한 경우

  • 함수 props를 자식에게 전달하고
  • 자식 컴포넌트가 React.memo로 감싸져 있으며
  • 부모 컴포넌트가 자주 리렌더링 되고
  • 자식 렌더링을 피하고 싶을 때

위 조건이 모두 충족되면 사용을 고려한다.

 

✅ 결론

자식에게 함수를 넘기지 않으면 => 일반 함수

자식이 memo 처리되어 있고, 함수 props를 받으면 => useCallback

반응형

'Library & Runtime > React' 카테고리의 다른 글

[React] 계산/렌더링 최적화: useMemo + React.memo 실험  (0) 2025.05.04
[React] 무거운 연산 최적화 : 일반 계산 vs useMemo  (0) 2025.05.03
[React] 컴포넌트 생명주기 : useEffect, 마운트, 언마운트  (0) 2025.05.01
[React/S3] 이미지 저장 구현 (+ CORS 에러 해결)  (2) 2024.11.16
'Library & Runtime/React' 카테고리의 다른 글
  • [React] 계산/렌더링 최적화: useMemo + React.memo 실험
  • [React] 무거운 연산 최적화 : 일반 계산 vs useMemo
  • [React] 컴포넌트 생명주기 : useEffect, 마운트, 언마운트
  • [React/S3] 이미지 저장 구현 (+ CORS 에러 해결)
올콩
올콩
콩 심은 데 콩 난다
  • 올콩
    콩스토리
    올콩
  • 전체
    오늘
    어제
    • 분류 전체보기 (140)
      • SSAFY (10)
      • Algorithm (67)
        • 이론 (5)
        • 백준 (BOJ) (61)
        • 프로그래머스 (1)
      • Language (9)
        • JavaScript (0)
        • TypeScript (0)
        • Java (9)
        • Python (0)
      • Library & Runtime (15)
        • React (13)
        • Node.js (2)
      • Framework (9)
        • 이론 (2)
        • Next.js (3)
        • Vue (4)
      • DevOps (3)
        • Git (3)
      • WEB (17)
        • HTML (9)
        • error (6)
        • etc (2)
      • Computer (5)
        • 자격증 (2)
        • tip (2)
        • etc (1)
      • CS (5)
        • Network (1)
        • Blockchain (4)
  • 블로그 메뉴

    • GitHub
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    kakaomap
    우선순위큐
    딕셔너리
    백준
    오블완
    블록체인
    bfs
    Java
    Error
    렌더링최적화
    SSAFYcial
    카카오맵
    vue
    소수
    github
    DP
    알고리즘
    파이썬
    Algorithm
    해시
    dfs
    싸피
    재귀
    SSAFY
    html5
    강의
    React
    자바
    Next.js
    티스토리챌린지
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
올콩
[React] 자식 컴포넌트 렌더링 : 일반 함수 vs useCallback
상단으로

티스토리툴바