React.memo()
로 컴포넌트를 감싸면 React는 불필요한 리렌더링을 방지하기 위해 shallow comparison(얕은 비교)를 수행한다. 성능 최적화용 기술이며, React 성능 튜닝 시 반드시 이해하고 있어야 하는 개념이다.
const MyComponent = React.memo(function MyComponent(props) {
// ...
});
React.memo()는 고차 컴포넌트(HOC)이다. props가 바뀌지 않았다면 컴포넌트 리렌더링을 건너뛴다. props가 바뀌었는지 판단할 때 얕은 비교(shallow comparison)를 사용한다.
얕은 비교는 객체의 1단계 속성만 비교하고, 내부 깊은 값까지는 확인하지 않는다. 원시 타입 값은 그대로 비교한다. 객체, 배열, 함수는 참조(주소)가 같아야 동일하다고 판단한다.
const a = { x: 1 };
const b = { x: 1 };
a === b; // false (내용 같아도 참조가 다름)
const c = a;
a === c; // true (같은 객체 참조)
즉, 렌더링마다 새 객체/배열/함수를 만들어 props로 넘기면 React.memo가 소용없게 된다.
부모 컴포넌트가 리렌더링될 때 React는 이전 props와 새로운 props를 shallow compare
const Child = React.memo(({ name }) => {
console.log("Child rendered");
return <div>{name}</div>;
});
function Parent() {
const [count, setCount] = useState(0);
return (
<>
<Child name="John" />
<button onClick={() => setCount(count + 1)}>+</button>
</>
);
}
1. 객체/배열/함수 props
const user = useMemo(() => ({ name: "John" }), []);
<Child user={user} />
2. custom 비교 함수 비용
3. props 비교 비용 자체
즉, 리렌더 → Virtual DOM 생성 → diff → DOM 업데이트가 기본 흐름이다.
const Child = React.memo(({ name }) => {
console.log("Child rendered");
return <div>{name}</div>;
});
props가 변하지 않았다면
➡️ 성능적으로 큰 최적화 효과를 얻을 수 있습니다.
React.memo는 props가 변하지 않으면 렌더링을 건너뛴다.
얕은 비교를 사용하기 때문에 객체/배열/함수 props는 주의가 필요하다.
useMemo, useCallback으로 참조를 고정하면 효과적이다.
custom 비교 함수도 가능하지만 비용이 크면 역효과다.
단순한 컴포넌트는 memo로 얻는 이득이 적고, 리스트·무거운 UI에서 효과가 크다.
React.memo는 불필요한 리렌더링을 줄이는 강력한 도구지만, 모든 컴포넌트에 무조건 적용하는 것은 권장되지 않습니다.
props 비교 비용과 컴포넌트 복잡도를 함께 고려해야 하며, 반복 렌더링되는 리스트 아이템이나 성능에 민감한 UI 컴포넌트에서 큰 효과를 발휘합니다.