프로그래밍/ReactJS

React 성능 최적화의 비밀 병기: useMemo 훅 완전 정복! 💡

shimdh 2025. 10. 15. 09:16
728x90

안녕하세요, React 개발자 여러분! 오늘은 React 애플리케이션의 속도를 한 단계 업그레이드할 수 있는 강력한 무기, useMemo 훅에 대해 깊이 파헤쳐보겠습니다. 만약 컴포넌트가 자꾸 느려지거나 불필요한 재렌더링으로 골치를 앓고 계시다면, 이 글을 끝까지 읽어보세요. useMemo가 여러분의 코드를 어떻게 더 효율적으로 만들어줄지, 이론부터 실전 예시까지 상세히 설명하겠습니다.

728x90

useMemo란 무엇인가요?

React 애플리케이션의 성능을 최적화하는 데 있어 useMemo 훅은 개발자에게 없어서는 안 될 강력한 도구입니다. 이 훅은 메모이제이션(memoization) 이라는 개념을 활용하여, 특정 값의 계산 결과를 캐시(저장)하고 필요할 때만 다시 계산하도록 함으로써 불필요한 렌더링 작업을 줄여줍니다.

간단히 말해, useMemo는 메모이제이션된 값을 반환하는 React 훅입니다. 이 훅은 두 가지 주요 인수를 받습니다:

  • 첫 번째 인수: 값을 계산하는 함수 (비용이 많이 드는 로직을 여기에 넣음).
  • 두 번째 인수: 의존성 배열(dependencies) – 배열 안의 값 중 하나라도 이전 렌더링과 다르면 함수를 다시 실행합니다.

의존성 배열 내의 값이 변경되지 않았다면, 캐시된 이전 값을 그대로 반환하여 재계산을 피합니다. 이는 컴포넌트가 재렌더링될 때마다 발생할 수 있는 비효율을 막아줍니다.

import React, { useMemo } from 'react';

const MyComponent = ({ data }) => {
  const memoizedValue = useMemo(() => {
    // 여기에 비용이 많이 드는 계산 로직을 작성합니다.
    // 예: 대규모 배열 정렬
    return data.sort((a, b) => a - b).reduce((sum, val) => sum + val, 0);
  }, [data]); // 의존성 배열: data가 변경될 때만 재계산

  return <div>{memoizedValue}</div>;
};

이처럼 useMemo는 React의 함수형 컴포넌트에서만 사용할 수 있으며, 클래스 컴포넌트에서는 React.memo나 다른 패턴으로 대체해야 합니다.

🎯 useMemo의 핵심 목적

useMemo를 사용하는 주된 목적은 성능 향상코드 안정성입니다. 구체적으로 살펴보죠:

  1. 성능 최적화
    모든 렌더링 주기마다 반복적으로 수행되는 비용이 많이 드는 계산을 방지합니다. 예를 들어, 대규모 데이터셋을 정렬하거나 복잡한 그래프를 그리는 등의 작업에 useMemo를 적용하면 애플리케이션의 전반적인 속도가 크게 향상됩니다. 결과적으로 사용자 경험(UX)이 부드러워지며, 모바일 기기에서도 안정적으로 동작합니다.
  2. 안정성 확보
    복잡한 객체나 함수의 안정적인 참조를 유지합니다. 특히 이 객체나 함수가 자식 컴포넌트의 props로 전달될 때 중요합니다. React는 props가 새 객체로 보이면 자식 컴포넌트를 재렌더링하는데, useMemo로 참조를 고정하면 불필요한 재렌더링을 막아 컴포넌트 트리 전체의 최적화를 돕습니다.

추가 팁: useMemo는 useCallback과 함께 사용하면 더 강력합니다. useCallback은 함수 참조를 메모이제이션하고, useMemo는 값이나 객체를 메모이제이션하죠.

🗓️ useMemo, 언제 사용해야 할까요?

useMemo는 언제나 사용해야 하는 만능 해결책은 아닙니다. 오히려 과도한 사용은 오버헤드를 초래할 수 있으니, 다음 시나리오에서 전략적으로 활용하세요:

  • 비용이 많이 드는 계산 수행 시: 대규모 데이터셋 정렬, 복잡한 필터링, 수학적 연산(예: 피보나치 수열 계산) 등 CPU 자원을 많이 소모하는 작업. 이런 경우 useMemo가 재계산을 50% 이상 줄일 수 있습니다.
  • 자식 컴포넌트에 객체/배열을 props로 전달할 때: React는 객체의 참조가 바뀌면 props 변경으로 간주합니다. useMemo로 객체를 메모이제이션하면 내용이 동일할 때 재렌더링을 피할 수 있습니다.
  • 의존성 변경이 없을 때 불필요한 재계산 회피: 컴포넌트 재렌더링(예: 상태 업데이트)으로 인한 반복 계산을 막고 싶을 때. 의존성 배열을 통해 "필요할 때만" 실행되도록 제어합니다.

반대로, 간단한 계산(예: 문자열 연결)에는 피하세요. useMemo의 메모리 할당 비용이 계산 비용보다 클 수 있습니다.

🚀 실용적인 예시: 사용자 목록 필터링

이제 실제로 useMemo의 매력을 느껴보죠. 사용자 목록을 이름으로 필터링하는 간단한 컴포넌트를 만들어 보겠습니다. useMemo를 사용하지 않으면 검색어나 사용자 데이터에 변화가 없더라도 컴포넌트 재렌더링(예: 다른 상태 변경) 시 필터링이 반복됩니다. 하지만 useMemo를 적용하면 의존성(사용자 목록, 검색어) 변경 시에만 실행됩니다.

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

const UserList = ({ users }) => {
  const [searchTerm, setSearchTerm] = useState('');

  // 필터링 로직을 최적화하기 위해 useMemo 사용
  const filteredUsers = useMemo(() => {
    console.log('사용자 필터링 중...'); // 이 로그는 의존성 변경 시에만 출력됩니다.
    return users.filter(user =>
      user.name.toLowerCase().includes(searchTerm.toLowerCase())
    );
  }, [users, searchTerm]); // users 또는 searchTerm이 변경될 때만 재계산

  return (
    <div>
      <input
        type="text"
        placeholder="Search Users"
        value={searchTerm}
        onChange={(e) => setSearchTerm(e.target.value)}
      />
      <ul>
        {filteredUsers.map(user => (
          <li key={user.id}>{user.name}</li>
        ))}
      </ul>
    </div>
  );
};

export default UserList;

설명

  1. 상태 관리: useState로 검색어(searchTerm)를 관리합니다. 입력 필드가 변경될 때마다 컴포넌트가 재렌더링됩니다.
  2. 메모이제이션을 통한 필터링: useMemo 내부 로직은 userssearchTerm이 변경될 때만 실행됩니다. 다른 UI 업데이트(예: 테마 변경)로 인한 재렌더링 시에도 필터링이 스킵되어 성능이 유지됩니다. 브라우저 콘솔에서 console.log를 확인해보세요 – 불필요한 재계산이 사라집니다!

이 예시를 확장하면, 1,000명 이상의 사용자 목록에서도 부드러운 검색을 구현할 수 있습니다.

📝 useMemo 사용을 위한 모범 사례

성능 최적화는 "신중함"이 핵심입니다. useMemo를 효과적으로 쓰기 위한 팁:

  • 성급한 최적화는 피하세요: 모든 값에 useMemo를 씌우지 마세요. 오히려 메모리 사용량이 증가할 수 있습니다. 프로파일러(React DevTools)를 사용해 병목 지점을 먼저 찾으세요.
  • 의존성을 정확하게 유지하세요: 메모이제이션 함수 내 모든 변수(상태, props)를 배열에 포함하세요. ESLint 규칙(react-hooks/exhaustive-deps)을 활성화하면 자동으로 체크합니다. 누락 시 스테일 클로저 버그가 발생할 수 있습니다.
  • 구현 전후 성능 측정: Chrome DevTools나 React Profiler로 FPS(프레임 속도)와 렌더링 횟수를 비교하세요. 때로는 React.memouseCallback 같은 다른 훅이 더 적합할 수 있습니다.
  • 추가 팁: 빈 의존성 배열 사용: [ ]로 빈 배열을 사용하면 컴포넌트 마운트 시 한 번만 계산됩니다. (주의: 이는 useEffect와 유사하지만 값 반환에 초점.)

✨ 결론

useMemo 훅은 React 애플리케이션에서 비용이 많이 드는 계산의 결과를 캐싱하여 성능을 최적화하는 데 필수적인 도구입니다. 특히 무거운 작업을 처리할 때 이 훅을 전략적으로 사용함으로써 더 빠르고 효율적인 애플리케이션을 구축할 수 있으며, 동시에 깔끔한 코드 관행을 유지할 수 있습니다.

728x90