memo

김병엽·2024년 9월 4일

성능 개선을 위한 "memoization", 그 중 "memo"에 대해 알아보자.


memo

const MemoizedComponent = memo(SomeComponent, arePropsEqual?)
  • props가 변경되지 않은 경우 구성 요소를 다시 렌더링하는 것을 건너뛸 수 있다.

  • React.memo()props 혹은 props의 객체를 비교할 때 얕은(shallow) 비교를 한다.


Parameters

  • Component: 메모화하려는 구성 요소.

  • (optional)arePropsEqual: 두 개의 인자를 허용하는 함수: 컴포넌트의 이전 props와 새 props. 이전 props와 새 props가 같은 경우 true를 반환해야 한다.
    일반적으로 이 함수를 지정하지 않는다. 기본적으로 React는 각 propsObject.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);

Usage

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가 변경 되지 않는다면 다음 렌더링 때 메모이징 된 내용을 그대로 사용하게 된다.


Updating a memoized component using state

  • 컴포넌트가 메모이제이션되더라도 state가 변경되면 여전히 다시 렌더링된다.

Updating a memoized component using a context

  • 컴포넌트가 메모이제이션되더라도 사용 중인 context가 변경되면 여전히 다시 렌더링된다.

메모이제이션은 부모에서 컴포넌트로 전달된 props와만 관련이 있다.


with Callback

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()을 이용해서 콜백 인스턴스를 보존시킨다.


Conclusion

  • 성능 최적화를 위해서만 메모에 의존해야 한다.

  • 대부분의 상황에서 React는 메모이징 된 컴퍼넌트의 리렌더링을 피할 수 있지만, 렌더링을 막기 위해 메모이제이션에 의존하면 안된다.


Reference

React/memo
TOASTUI

profile
선한 영향력을 줄 수 있는 개발자가 되자, 되고싶다.

0개의 댓글