성능 개선을 위한 "memoization", 그 중 "memo"에 대해 알아보자.
const MemoizedComponent = memo(SomeComponent, arePropsEqual?)
props가 변경되지 않은 경우 구성 요소를 다시 렌더링하는 것을 건너뛸 수 있다.
React.memo()는 props 혹은 props의 객체를 비교할 때 얕은(shallow) 비교를 한다.
Component: 메모화하려는 구성 요소.
(optional)arePropsEqual: 두 개의 인자를 허용하는 함수: 컴포넌트의 이전 props와 새 props. 이전 props와 새 props가 같은 경우 true를 반환해야 한다.
일반적으로 이 함수를 지정하지 않는다. 기본적으로 React는 각 props를 Object.is를 이용해 비교한다.
React.memo(Component, [areEqual(prevProps, nextProps)]);
function moviePropsAreEqual(prevMovie, nextMovie) {
return (
prevMovie.title === nextMovie.title &&
prevMovie.releaseDate === nextMovie.releaseDate
);
}
const MemoizedMovie2 = React.memo(Movie, moviePropsAreEqual);
export function Movie({ title, releaseDate }) {
return (
<div>
<div>Movie title: {title}</div>
<div>Release date: {releaseDate}</div>
</div>
);
}
export const MemoizedMovie = React.memo(Movie);
title이나 releaseData 같은 props가 변경 되지 않는다면 다음 렌더링 때 메모이징 된 내용을 그대로 사용하게 된다.
state가 변경되면 여전히 다시 렌더링된다. context가 변경되면 여전히 다시 렌더링된다. ❗ 메모이제이션은 부모에서 컴포넌트로 전달된
props와만 관련이 있다.
function Logout({ username, onLogout }) {
return <div onClick={onLogout}>Logout {username}</div>;
}
const MemoizedLogout = React.memo(Logout);
function MyApp({ store, cookies }) {
return (
<div className="main">
<header>
<MemoizedLogout
username={store.username}
onLogout={() => cookies.clear()}
/>
</header>
{store.content}
</div>
);
}
함수의 동등성이란 함정 때문에, 메모이제이션을 적용할 때는 콜백을 받는 컴퍼넌트 관리에 주의해야한다.
리렌더를 할 때 마다 부모 함수가 다른 콜백 함수의 인스턴스를 넘길 가능성이 있다.
동일한 username 값이 전달되더라고, MemoizedLogout은 새로운 onLogout 콜백 때문에 리렌더링을 하게 된다.
const MemoizedLogout = React.memo(Logout);
function MyApp({ store, cookies }) {
const onLogout = useCallback(() => {
cookies.clear();
}, []);
return (
<div className="main">
<header>
<MemoizedLogout username={store.username} onLogout={onLogout} />
</header>
{store.content}
</div>
);
}
useCallback()을 이용해서 콜백 인스턴스를 보존시킨다.
성능 최적화를 위해서만 메모에 의존해야 한다.
대부분의 상황에서 React는 메모이징 된 컴퍼넌트의 리렌더링을 피할 수 있지만, 렌더링을 막기 위해 메모이제이션에 의존하면 안된다.