우당탕탕

React useMemo와 useCallback, 진짜 필요할 때만 쓰는 법 알려드려요 본문

언어/JavaScript

React useMemo와 useCallback, 진짜 필요할 때만 쓰는 법 알려드려요

모찌모찝 2026. 7. 18. 19:35

사실 제가 React를 처음 배울 때 useMemouseCallback이 뭔지도 잘 몰랐어요. 용어부터 어렵고, 무슨 상황에 쓰는지 감이 안 잡혀서 그냥 무작정 쓰다가 오히려 성능이 더 안 좋아진 적도 있었거든요.

그래서 이 글에서는 React 초보분들이 useMemouseCallback을 언제, 어떻게 써야 하는지, 그리고 정말 필요한 상황인지 구분하는 방법까지 모두 알려드릴게요. 저도 직접 구현하면서 깨달은 게 많아서 경험담 위주로 쉽게 써봤어요.

React useMemo와 useCallback, 이게 뭔지부터 제대로 짚기

많이 헷갈려 하시는 게 이 두 훅이 뭔지, 그리고 뭔가 비슷해 보여서 언제 써야 할지 모르겠다는 점인데요. 간단하게 말하면 useMemo는 "값을 기억"하는 용도고, useCallback은 "함수를 기억"하는 용도입니다.

즉, 어떤 계산 결과값을 재사용하고 싶을 때는 useMemo, 함수를 새로 만들지 않고 항상 같은 함수를 써야 할 때는 useCallback을 쓰는 거예요. 이것만 알아도 절반은 이해한 거랍니다.

React useMemo useCallback 진짜 필요할 때만 쓰는 법 관련 이미지

React useMemo useCallback 진짜 필요할 때만 쓰는 법 관련 정보

저는 이렇게 배웠어요, useMemo 간단 사용법

사실 이 부분이 제일 쉽거든요. 그냥 어려운 계산(예를 들어 데이터 필터링, 복잡한 배열 처리 등)이 있고, 이 계산 결과가 자주 변하지 않는다면 useMemo로 메모이제이션(기억)해주면 렌더링 때마다 불필요한 계산을 줄일 수 있어요.

// 복잡한 계산을 useMemo로 감싸 처리하기
import React, { useMemo, useState } from 'react';

function FilteredList({ items, filter }) {
  // items 배열에서 filter 조건에 맞는 것만 추립니다
  const filteredItems = useMemo(() => {
    console.log('필터링 연산 수행');
    return items.filter(item => item.includes(filter));
  }, [items, filter]);

  return (
    {filteredItems.map(item =>
  • {item}
  • )}

  );
}

export default function App() {
  const [filter, setFilter] = useState('');
  const items = ['apple', 'banana', 'grape', 'orange'];

  return (
setFilter(e.target.value)} placeholder="필터 입력" />

  );
}

위 예시에서 filteredItemsitemsfilter가 바뀔 때만 다시 계산되고, 그렇지 않으면 이전에 계산한 결과를 그대로 쓰니까 훨씬 효율적이죠.

useCallback, 함수 메모리가 왜 필요할까?

그런데 여기서 많이 헷갈리는 게 "왜 함수도 기억해야 하냐"는 거예요. 그냥 함수 새로 만드는 거랑 뭐가 다르냐고요. 저도 처음엔 그랬어요.

하지만 React에서 컴포넌트가 리렌더링되면 함수도 새로 만들어지기 때문에, 이걸 자식 컴포넌트에 props로 넘겨줄 경우, 자식 컴포넌트가 불필요하게 다시 렌더링될 수 있다는 점이 문제예요.

그래서 useCallback으로 메모리제이션 해두면 항상 같은 함수 참조값을 쓰기 때문에 자식 컴포넌트가 딱 필요한 경우에만 다시 렌더링돼서 성능 최적화에 도움이 됩니다.

React useMemo useCallback 진짜 필요할 때만 쓰는 법 직접 정리한 자료

React useMemo useCallback 진짜 필요할 때만 쓰는 법 관련 정보

간단한 useCallback 예제와 핵심 포인트

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

const Child = React.memo(({ onClick }) => {
  console.log('Child 렌더링');
  return 클릭;
});

export default function App() {
  const [count, setCount] = useState(0);

  // useCallback으로 함수 메모리 유지
  const handleClick = useCallback(() => {
    setCount(prev => prev + 1);
  }, []);

  return (

카운트: {count}


  );
}

이 예제에서 ChildReact.memo로 감쌌는데요, 만약 handleClick을 그냥 새롭게 만든 함수로 넘기면, 부모가 리렌더링될 때마다 Child도 렌더링돼요. 그런데 useCallback을 쓰니까 함수 참조가 유지돼서 Child가 불필요하게 렌더링되지 않았답니다.

솔직히 이렇게 다 쓰면 오히려 성능이 안 좋아질 수 있어요

근데 여기서 많이들 오해하는 게, useMemouseCallback을 무조건 남발하는 거예요. 저도 그랬고요. 그런데 이 훅들이 모두 메모리와 비교 작업, 그리고 훅 자체 관리 비용이 있어서, 너무 자잘하게 적용하면 오히려 렌더링이 느려질 수 있답니다.

그래서 진짜 불필요한 리렌더링이 문제되고, 해당 계산이나 함수 생성 비용이 크다는 게 명확할 때만 써야 해요. 단순히 "기본 상태 변화 때문에 리렌더링이 되는 건 괜찮아"라고 생각하는 게 정신 건강에 좋아요.

React useMemo useCallback 진짜 필요할 때만 쓰는 법 참고 사진

React useMemo useCallback 진짜 필요할 때만 쓰는 법 관련 정보

어떤 상황에서 꼭 써야 하는지 실제 경험 공유

제가 프로젝트 하면서 딱 썼던 경우를 이야기해볼게요.

  • 복잡한 리스트 필터링, 정렬 같은 무거운 계산이 잦을 때 useMemo로 메모이제이션해서 렌더링 비용 줄였고
  • 자식 컴포넌트가 많고, 부모가 자주 리렌더링되는데 함수형 props를 넘겨줘야 해서 useCallback으로 함수 참조 고정해서 불필요한 렌더링 방지
  • 하지만 단순히 state 값을 변경할 때마다 쓸데없이 이 훅들로 감싸서 오히려 복잡해지고 버그 원인이 됐던 경험

결국 코드가 너무 난해해지면 유지보수가 어려워지고, 잘못 쓰면 성능 악화도 심하다는 걸 뼈저리게 느꼈어요.

여기서 많이들 헷갈려하는 부분 설명!

Q. useMemo랑 useCallback 쓰면 무조건 성능 좋아지나요?

A. 아니에요! 오히려 너무 작은 연산이나 함수에 쓰면 오히려 렌더링 시간이 늘어나요. 메모리 저장하고 비교하는 비용이 크거든요. 꼭 "무거운 계산이나 자식 컴포넌트 리렌더링 최적화가 필요할 때"만 쓰세요.

Q. useCallback 안 쓰고 그냥 함수 새로 만들어서 넘기면 무조건 안 좋은 건가요?

A. 꼭 그런 건 아니에요. 자식 컴포넌트가 단순하면 상관없어요. React.memoPureComponent를 쓰고, 함수가 너무 무거워서 새로 만드는 게 부담될 때만 고민해보면 됩니다.

Q. useMemo랑 useCallback 함께 써야 하나요?

A. 용도가 다르니까 상황에 맞게 골라 쓰세요. 값 계산엔 useMemo, 함수 참조 유지엔 useCallback이에요.

마치며, 제가 제안하는 쓰는 법 기준 정리

저는 지금 이렇게 쓰고 있어요.

  • 성능 문제 의심될 때 React DevTools로 프로파일링 먼저 하고
  • 복잡한 값 계산에 useMemo 활용
  • 자식 컴포넌트가 React.memo일 때 함수 props는 useCallback으로 감싸기
  • 그 외엔 너무 남발하지 않기
  • 코드가 지나치게 복잡해졌다면 잠시 빼고 성능을 다시 체크

이게 저처럼 React 입문하시는 분들한테 좀 더 실용적이고 스트레스 덜 받는 방법인 것 같아요. 저도 처음 쓸 땐 복잡하고 헷갈렸지만, 이렇게 정리해놓으니까 훨씬 편하더라고요.

Comments