| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | ||||||
| 2 | 3 | 4 | 5 | 6 | 7 | 8 |
| 9 | 10 | 11 | 12 | 13 | 14 | 15 |
| 16 | 17 | 18 | 19 | 20 | 21 | 22 |
| 23 | 24 | 25 | 26 | 27 | 28 | 29 |
| 30 | 31 |
- 스프링부트
- 정규식
- html
- Array
- 배열
- java테스트
- HashMap
- js
- Eclipse
- 문자열
- 자바문법
- SpringBoot
- Visual Studio Code
- input
- 인텔리제이
- Java
- junit5
- ArrayList
- vscode
- string
- 자바
- CSS
- IntelliJ
- junit
- 테스트자동화
- 단위테스트
- javascript
- 자바스크립트
- list
- math
- Today
- Total
어제 오늘 내일
[React] useMemo 사용법: 불필요한 연산을 줄이는 메모이제이션 본문
React 애플리케이션이 커지다 보면 렌더링 성능이 신경 쓰이기 시작합니다. 특히 무거운 계산이 매 렌더링마다 반복되면 앱이 느려질 수 있죠. 이럴 때 사용하는 것이 바로 useMemo Hook입니다. 이 글에서는 useMemo가 무엇인지, 언제 쓰고 언제 쓰지 말아야 하는지 예제와 함께 알아보겠습니다.
메모이제이션이란?
useMemo를 이해하려면 먼저 메모이제이션(Memoization) 개념을 알아야 합니다. 메모이제이션은 이미 계산한 결과를 저장해 두었다가, 같은 입력이 들어오면 다시 계산하지 않고 저장된 값을 재사용하는 최적화 기법입니다.
쉽게 말해, "한 번 계산한 건 기억해뒀다가 그대로 꺼내 쓰자"는 아이디어입니다.
문제 상황: 매 렌더링마다 반복되는 무거운 계산
먼저 useMemo가 없을 때 어떤 문제가 생기는지 살펴보겠습니다.
function ProductList({ products, filter }) {
// 이 계산은 컴포넌트가 렌더링될 때마다 매번 실행됨
// products가 1만 개라면 매 렌더링마다 1만 번 순회 → 성능 저하
const filteredProducts = products.filter(product =>
product.name.includes(filter)
);
return (
<ul>
{filteredProducts.map(p => <li key={p.id}>{p.name}</li>)}
</ul>
);
}이 컴포넌트는 filter가 바뀌지 않았더라도, 부모 컴포넌트가 리렌더링되면 함께 리렌더링되면서 filter() 연산을 매번 다시 실행합니다. 목록이 크거나 계산이 복잡하다면 불필요한 낭비가 발생합니다.
useMemo로 해결하기
useMemo를 사용하면 의존성이 바뀔 때만 계산을 다시 하도록 만들 수 있습니다.
import { useMemo } from 'react';
function ProductList({ products, filter }) {
// useMemo(계산 함수, 의존성 배열) 형태로 사용
// products나 filter가 바뀔 때만 필터링을 다시 실행
// 둘 다 그대로면 이전에 계산해둔 결과를 그대로 재사용
const filteredProducts = useMemo(() => {
return products.filter(product =>
product.name.includes(filter)
);
}, [products, filter]); // 이 배열의 값이 바뀌어야만 재계산
return (
<ul>
{filteredProducts.map(p => <li key={p.id}>{p.name}</li>)}
</ul>
);
}이제 filter와 products가 그대로라면, 다른 이유로 리렌더링이 일어나도 필터링 연산은 다시 실행되지 않습니다.
useMemo의 기본 문법
const memoizedValue = useMemo(() => {
// 무겁거나 반복하고 싶지 않은 계산
return computeExpensiveValue(a, b);
}, [a, b]); // 의존성 배열- 첫 번째 인자: 값을 계산해서 반환하는 함수
- 두 번째 인자: 의존성 배열(dependency array)
- 배열 안의 값이 하나라도 바뀌면 계산 함수를 다시 실행
- 값이 그대로면 이전에 저장한 결과를 재사용
의존성 배열은 useEffect와 동일한 규칙으로 동작합니다.
또 다른 활용: 참조 동일성(Referential Equality) 유지
useMemo는 무거운 계산뿐 아니라, 객체나 배열의 참조값을 유지하는 데도 유용합니다. 이전 글에서 다뤘던 Context 예제가 좋은 사례입니다.
function App() {
const [user, setUser] = useState({ name: "홍길동" });
// ❌ 매 렌더링마다 새로운 객체가 생성됨
// 참조값이 매번 달라져서, 이 값을 받는 컴포넌트가 불필요하게 리렌더링됨
const value = { user, setUser };
return <UserContext.Provider value={value}>...</UserContext.Provider>;
}function App() {
const [user, setUser] = useState({ name: "홍길동" });
// ✅ user가 바뀔 때만 새 객체를 생성하고, 그 외엔 같은 객체를 재사용
// 참조값이 유지되므로 불필요한 리렌더링을 방지
const value = useMemo(() => ({ user, setUser }), [user]);
return <UserContext.Provider value={value}>...</UserContext.Provider>;
}자바스크립트에서 객체는 내용이 같아도 새로 만들면 서로 다른 참조로 취급됩니다. React.memo로 감싼 자식 컴포넌트나 Context에 객체를 넘길 때, 이 참조 동일성을 유지하는 것이 성능 최적화의 핵심입니다.
useMemo vs useCallback
useMemo와 자주 헷갈리는 것이 useCallback입니다. 둘의 관계를 간단히 정리하면 이렇습니다.
// useMemo는 "값"을 메모이제이션
const memoizedValue = useMemo(() => computeValue(a, b), [a, b]);
// useCallback은 "함수"를 메모이제이션
const memoizedFn = useCallback(() => doSomething(a, b), [a, b]);
// 사실 useCallback은 useMemo로 함수를 감싼 것과 동일함
const memoizedFn = useMemo(() => () => doSomething(a, b), [a, b]);
| 구분 | useMemo | useCallback |
| 메모이제이션 대상 | 계산된 값 | 함수 자체 |
| 반환값 | 함수 실행 결과 | 함수 그 자체 |
| 주요 용도 | 무거운 계산, 참조 유지 | 자식에 함수를 props로 전달할 때 |
남용하지 말아야 하는 이유
useMemo는 공짜가 아닙니다. React는 의존성 배열을 비교하고, 이전 값을 메모리에 저장하는 비용을 치릅니다. 따라서 모든 값에 useMemo를 붙이는 것은 오히려 손해입니다.
// ❌ 이런 단순한 계산에는 useMemo가 오히려 오버헤드
// 덧셈보다 useMemo 자체의 비교 비용이 더 클 수 있음
const sum = useMemo(() => a + b, [a, b]);
// ✅ 그냥 계산하는 게 더 빠르고 깔끔함
const sum = a + b;언제 useMemo를 사용해야 할까?
다음 상황에 해당할 때 useMemo 도입을 고려하세요.
- 계산 비용이 실제로 비쌀 때: 큰 배열의 정렬, 필터링, 복잡한 반복 연산 등
- 객체/배열의 참조 동일성이 필요할 때:
React.memo로 감싼 컴포넌트나 Context에 전달하는 값,useEffect의 의존성으로 쓰이는 객체 - 측정을 통해 실제 병목을 확인했을 때: 성능 문제가 실제로 존재하는지 먼저 확인하는 것이 중요
반대로 단순 계산이나 성능 문제가 없는 곳에서는 useMemo를 붙이지 않는 것이 더 좋습니다. "일단 붙이고 보자"가 아니라, 측정 후 필요한 곳에만 적용하는 것이 좋은 습관입니다.
마무리
useMemo는 불필요한 재계산을 막아 성능을 최적화하는 강력한 도구입니다. 무거운 계산을 캐싱하거나 객체의 참조값을 유지하는 두 가지 용도로 주로 쓰입니다. 다만 모든 곳에 남용하면 오히려 코드가 복잡해지고 성능에 악영향을 줄 수 있으니, "이 계산이 정말 비싼가?", "참조 동일성이 필요한가?"를 스스로 물어본 뒤 적용하는 것이 핵심입니다.
Tip: React 19부터는 React Compiler가 이런 메모이제이션을 자동으로 처리해주는 방향으로 발전하고 있습니다. 하지만 원리를 이해하는 것은 여전히 중요하며, 수동 최적화가 필요한 상황도 많으니 useMemo의 동작 방식을 확실히 익혀두는 것을 추천합니다.
'IT > React' 카테고리의 다른 글
| [ React ] useCallback 사용법: 함수를 메모이제이션해 리렌더링 최적화하기 (0) | 2026.08.07 |
|---|---|
| [React] JSX 기초 완벽 가이드: React의 화면을 그리는 문법 (0) | 2026.08.03 |
| [React] Context API 완벽 가이드: Props Drilling 없이 상태 공유하기 (0) | 2026.08.03 |
| [React] props와 state 차이 이해하기, 상태 끌어올리기 (0) | 2026.08.02 |
| [React] useEffect 사용법 (개념, 의존성 배열, Clean-up 함수) (0) | 2026.08.02 |