개요
memo
는 컴포넌트의 props가 바뀌지 않으면 리렌더를 건너뛰도록 해주는 React의 성능 최적화 API입니다. 부모가 리렌더되어도 props가 동일하다면 자식 컴포넌트의 리렌더를 방지할 수 있습니다. 단, memoization은 최적화일 뿐, 리렌더를 100% 막는 보장은 아닙니다.
const MemoizedComponent = memo(SomeComponent, arePropsEqual?);
Reference
memo(Component, arePropsEqual?)
컴포넌트를 memo로 감싸면, memoized 버전의 컴포넌트가 반환됩니다. 부모가 리렌더되어도 props가 바뀌지 않으면 자식 컴포넌트는 리렌더되지 않습니다.
- 파라미터
Component
: 메모이즈할 컴포넌트(함수형, forwardRef 등 모두 가능). 원본 컴포넌트는 수정되지 않고, 새 memoized 컴포넌트가 반환됩니다.arePropsEqual?
(optional): 이전 props와 새 props를 받아 true(동일) 또는 false(다름)를 반환하는 비교 함수. 기본적으로 Object.is로 얕은 비교(shallow equality)를 합니다. 대부분의 경우 생략해도 됩니다.
- 반환값
- memoized 컴포넌트(React 컴포넌트 타입). 원본과 동일하게 동작하지만, props가 바뀌지 않으면 리렌더를 건너뜁니다.
사용법
props가 바뀌지 않을 때 리렌더 건너뛰기
import { memo } from 'react';
const Greeting = memo(function Greeting({ name }) {
return <h1>Hello, {name}!</h1>;
});
export default Greeting;
- 부모가 리렌더되어도 name이 바뀌지 않으면 Greeting은 리렌더되지 않습니다.
- props, state, context가 모두 동일하면 항상 같은 결과를 반환해야 합니다(순수 렌더링).
memoized 컴포넌트의 state/context 변화
- memoized 컴포넌트도 자신의 state가 바뀌거나, 내부에서 사용하는 context 값이 바뀌면 리렌더됩니다. memo는 부모로부터 전달받는 props에만 영향을 미칩니다.
props가 객체/배열/함수일 때
- memo는 props를 얕은 비교(Object.is)로 판단합니다. 매번 새로 생성되는 객체/배열/함수는 값이 같아도 참조가 달라서 리렌더가 발생합니다.
- useMemo/useCallback으로 props를 메모이즈하거나, props를 최대한 단순하게(원시값 위주) 전달하세요.
function Page() {
const [name, setName] = useState('Taylor');
const [age, setAge] = useState(42);
const person = useMemo(() => ({ name, age }), [name, age]);
return <Profile person={person} />;
}
const Profile = memo(function Profile({ person }) {
// ...
});
- 더 좋은 방법은 props를 객체로 묶지 않고 개별 값으로 전달하는 것입니다.
커스텀 비교 함수 사용
- props 구조가 복잡하거나, 얕은 비교로 충분하지 않을 때 두 번째 인자로 비교 함수를 전달할 수 있습니다.
const Chart = memo(function Chart({ dataPoints }) {
// ...
}, arePropsEqual);
function arePropsEqual(prev, next) {
return (
prev.dataPoints.length === next.dataPoints.length &&
prev.dataPoints.every((oldPoint, i) => {
const newPoint = next.dataPoints[i];
return oldPoint.x === newPoint.x && oldPoint.y === newPoint.y;
})
);
}
- 비교 함수는 모든 props(함수 포함)를 반드시 비교해야 하며, deep equality는 성능에 주의해야 합니다.
트러블슈팅
객체/배열/함수 props로 인해 리렌더가 발생하는 경우
- 부모에서 매번 새 객체/배열/함수를 생성해 props로 넘기면, memo가 있어도 리렌더가 발생합니다. useMemo/useCallback으로 참조를 고정하거나, props를 단순화하세요.
memo를 남용해도 괜찮은가?
- memo는 성능 최적화일 뿐, 코드가 동작하지 않는 문제를 해결하는 용도로 쓰면 안 됩니다. 실제로 렌더링 비용이 크고, props가 자주 바뀌지 않는 컴포넌트에만 적용하세요.
- memo를 남용하면 코드 가독성이 떨어질 수 있습니다.
참고 및 주의사항
- memo는 props가 바뀌지 않을 때만 리렌더를 건너뜁니다. state/context 변화에는 영향을 주지 않습니다.
- 비교 함수는 모든 props(특히 함수형 props)까지 정확히 비교해야 하며, deep equality는 성능에 주의하세요.
- memoization은 최적화일 뿐, 리렌더를 100% 막는 보장은 아닙니다.
반응형