안녕하세요 2년차 개발자입니다.
카페에서 커피마시면서
코딩하기를 좋아해요.

Software Engineer

React Memo

복습 차원에서 React Memo 에 대해 알아본다.

리액트에는 memo 라는 메서드가 있다. React.memo 는 HOC(고차 컴포넌트) 다.

이게 왜 있을까?

  • React 는 가상DOM 을 사용하기 때문에, native DOM 으로 반영하기 전에 deps 에 포함된 이전 속성(props)과 변경된 속성을 비교해서 리렌더링을 해주는데 이때, React.memo() 를 감싸게 되면 감싸여진 컴포넌트의 렌더링 결과물을 메모리에 기억(memoize)하고 있으므로 불필요한 렌더링(Render tree 생성)을 건너뛴다.

  • 기본적으로 얕은 비교를 한다. 1 on 1 prop 비교 등 커스텀한 비교도 가능하다.

// facebook - react 구현 코드 일부

// true - 같다 ( 리렌더링 X )
// false - 다르다 ( 리렌더링 O )
function shallowEqual(objA: mixed, objB: mixed): boolean {
  if (is(objA, objB)) {
    return true;
  }

  if (
    typeof objA !== 'object' ||
    objA === null ||
    typeof objB !== 'object' ||
    objB === null
  ) {
    return false;
  }

  const keysA = Object.keys(objA);
  const keysB = Object.keys(objB);

  if (keysA.length !== keysB.length) {
    return false;
  }

  // Test for A's keys different from B.
  for (let i = 0; i < keysA.length; i++) {
    if (
      !hasOwnProperty.call(objB, keysA[i]) ||
      !is(objA[keysA[i]], objB[keysA[i]])
    ) {
      return false;
    }
  }

  return true;
}

export default shallowEqual;

어떻게 쓰면 좋을까?

  • 동일한 props 라도 부모에서 콜백 함수를 넘겨 받는 경우에 useCallback ( 함수 재선언 방지 = 동일 인스턴스(참조값) ) hook 을 적용하지 않으면, 새로운 콜백 함수 인스턴스를 생성해 넘겨 주기 때문에 ( js 특, 함수 = 객체 ) 리렌더링이 발생한다. 효과적인 메모이제이션을 위해서 콜백 함수 관리가 필요하다. ( 인라인 스타일과 비슷? style object 를 매번 새로운 object로 인식 -> 리렌더링 발생 )

React.memo !== useMemo

  • useMemo 는 메모이제이션된 값을 반환하는 hook 이다.
  • computeExpensiveValue 에 적용하면 성능상 이점이 뚜렷해진다!
  • deps 필수! 없으면 쓸 필요 없음.
// useMemo 구현 일부
function useMemo<T>(nextCreate: () => T, deps: Array<mixed> | void | null): T {
  currentlyRenderingComponent = resolveCurrentlyRenderingComponent();
  workInProgressHook = createWorkInProgressHook();

  const nextDeps = deps === undefined ? null : deps;

  if (workInProgressHook !== null) {
    const prevState = workInProgressHook.memoizedState;
    if (prevState !== null) {
      if (nextDeps !== null) {
        const prevDeps = prevState[1];
        if (areHookInputsEqual(nextDeps, prevDeps)) {
          return prevState[0];
        }
      }
    }
  }

기타 잡생각

  • solid.js => 리액트처럼 memo 이런거 필요없음. https://www.solidjs.com/

인사이트 참고 - https://news.ycombinator.com/