🚀 React.memo 완벽 정리: 컴포넌트 리렌더링을 막는 고급 최적화 기법
React.memo
는 React에서 제공하는 고차 컴포넌트(Higher-Order Component)입니다.
컴포넌트의 props가 바뀌지 않으면, 해당 컴포넌트를 리렌더링하지 않도록 만들어줍니다.
즉, 불필요한 렌더링을 방지하여 성능을 최적화할 수 있는 도구예요.
하지만 언제, 왜, 어떻게 써야 할지를 제대로 이해하지 못하면 오히려 디버깅이 어려운 코드가 될 수도 있습니다.
이번 글에서는 React.memo의 개념, 사용법, 작동 원리, 주의점까지 심도 있게 정리해봅니다.
🔍 React.memo란?
React.memo는 함수형 컴포넌트를 메모이제이션(memoization)하여, props가 변경되지 않는 한 컴포넌트를 다시 렌더링하지 않습니다.
const MemoizedComponent = React.memo(OriginalComponent);
이렇게 감싸면, props가 변경되지 않는 한 컴포넌트가 React의 Virtual DOM diff 과정에서 제외됩니다.
✅ 기본 사용 예시
// 자식 컴포넌트
const Child = React.memo(({ name }) => {
console.log('Child 렌더링');
return <p>안녕하세요, {name}</p>;
});
// 부모 컴포넌트
function Parent() {
const [count, setCount] = useState(0);
return (
<>
<Child name="철수" />
<button onClick={() => setCount(count + 1)}>+1</button>
</>
);
}
위 코드에서 Child는 props(name)가 바뀌지 않기 때문에 재렌더링되지 않습니다. 콘솔 로그를 찍어보면 확인할 수 있어요.
🔄 리렌더링 원리 다시 보기
React는 부모 컴포넌트가 리렌더링되면 자식 컴포넌트도 기본적으로 함께 리렌더링합니다.
이때 자식 컴포넌트에 전달되는 props가 이전과 동일한 값이라도 함수나 객체이면 새로 생성된 것으로 간주됩니다.
이때React.memo
를 사용하면, 이전 props와 새 props가 같은 경우
자식 컴포넌트의 리렌더링을 막을 수 있습니다.
⚙️ React.memo 내부 작동 방식
React.memo
는 Object.is()
를 사용하여 props를 얕은 비교(shallow compare)합니다.
즉, 다음과 같은 경우에만 리렌더링을 막습니다:
- 기본 타입 값(숫자, 문자열 등)의 값이 이전과 같을 때
- 객체나 배열, 함수의 참조가 동일할 때
아래는 비교 예시입니다:
const obj1 = { a: 1 };
const obj2 = { a: 1 };
console.log(obj1 === obj2); // false (참조 다름)
그래서 부모에서 함수를 매번 새로 선언하거나, 객체를 만들어서 넘기면 React.memo
가 무용지물이 될 수 있어요.
🔧 해결 방법: useCallback & useMemo와 함께 사용
함수 props → useCallback
const handleClick = useCallback(() => {
console.log("클릭");
}, []);
객체 props → useMemo
const style = useMemo(() => ({ color: "blue" }), []);
→ 이렇게 하면 props의 참조값이 고정되어 React.memo의 효과가 극대화됩니다.
📌 커스텀 비교 함수 사용 (areEqual)
React.memo
는 기본적으로 얕은 비교를 하지만, 두 번째 인자로 비교 함수를 전달할 수도 있어요.
const Memoized = React.memo(MyComponent, (prevProps, nextProps) => {
return prevProps.value === nextProps.value;
});
→ props 구조가 복잡하거나, 특정 값만 비교하고 싶을 때 유용합니다.
📊 실전에서 자주 쓰는 패턴
- 리스트 컴포넌트 렌더링 최적화 (예: 채팅 메시지 리스트)
- Props가 자주 바뀌지 않는 컴포넌트
- 함수형 컴포넌트에서 useCallback과 함께 자식 컴포넌트를 감쌀 때
- 다수의 고정 UI 요소 렌더링 (아이콘, 버튼 등)
🧪 언제 React.memo를 쓰지 말아야 할까?
React.memo는 props 비교에 따른 비용이 발생합니다. 때로는 이 비교 과정이 컴포넌트를 리렌더링하는 것보다 오히려 비효율적일 수도 있어요.
아래와 같은 경우에는 굳이 사용하지 않아도 됩니다:
- 컴포넌트가 매우 가볍고, 렌더링 비용이 낮은 경우
- props가 자주 바뀌는 경우
- 모든 props가 새로운 참조(함수/객체)인 경우
⚠️ 실수하기 쉬운 사례
1. 객체나 함수 props를 매 렌더링마다 새로 생성
// ❌ React.memo 효과 없음
<Child obj={{ a: 1 }} />
→ 매 렌더링마다 새로운 참조가 생성되므로 React.memo는 무용지물
2. useCallback 없이 함수 props 전달
// ❌ 새로운 함수 참조 생성됨
<Child onClick={() => console.log('클릭')} />
→ 자식 컴포넌트가 매번 리렌더링됨
✅ useCallback 적용
const handleClick = useCallback(() => console.log('클릭'), []);
<Child onClick={handleClick} />
📚 추천 공식 리소스
✅ 마무리 정리
- React.memo는 props가 바뀌지 않으면 컴포넌트 리렌더링을 방지합니다.
- 얕은 비교(Object.is)만 수행하기 때문에 참조형 props는 주의가 필요합니다.
- useCallback / useMemo를 함께 쓰면 최적화 효과가 커집니다.
- 무조건 사용하기보단, 성능 병목 구간에만 전략적으로 사용하는 것이 베스트!
React.memo는 성능을 향상시키는 칼이 될 수도 있고,
쓸데없이 코드만 복잡하게 만드는 짐이 될 수도 있습니다.
무조건 적용이 아니라, 필요한 곳에 똑똑하게 적용해보세요!
다음 글에서는 React.memo + useCallback을 조합한 고급 컴포넌트 최적화 전략을 다뤄볼 예정입니다 😎
'일상이 개발' 카테고리의 다른 글
React DevTools 완전 정복: 리렌더링 감지와 성능 최적화 방법 가이드 (0) | 2025.04.05 |
---|---|
React.memo + useCallback 조합으로 컴포넌트 리렌더링을 막아보자! (0) | 2025.04.05 |
React useMemo & useCallback 완벽 이해: 언제, 왜, 어떻게 사용하는가 (0) | 2025.04.05 |
React useEffect 완벽 정리: 의존성 배열부터 클린업까지 이해하기 (0) | 2025.04.05 |
React의 핵심, props vs state: 언제, 왜, 어떻게 사용할까? (0) | 2025.04.04 |