フックマスターになりたい (3): useMemo & useCallback!

9rganizedChaos·2021년 9월 26일
0
post-thumbnail

RandomNum Generator

본래 useMemo와 useCallback은 렌더링 성능을 최적화하기 위한 훅들이다. 특히 복잡한 계산이나 로직이 수반되는 값, 또는 함수가 아니라면 굳이 사용할 필요가 없다. 그러나 조금 다른 방식으로 useMemo와 useCallback에 접근해볼 수 있지 않을까? 이를 테면, useMemo를 꼭 써야 하는 상황이 생길 때도 있지 않을까? 완벽한 해답을 찾은 것은 아니지만, 얼추 비슷한 상황을 가정해보았다.

오늘 포스팅에서 다룰 것은 랜덤 넘버 제너레이터이다!
쉽게 말해 maxNum을 설정하면 1부터 maxNum까지 숫자 중 랜덤한 숫자를 출력해주는 앱이다.

CodePen으로 간단하게 만들어보았다!

왜 마우스를 호버할 때마다 랜덤 넘버가 변경될까?

위 랜덤 넘버 제너레이터를 살펴보았다면 뭔가 문제가 있다는 점을 알 수 있다! 바로 RandomNum 컴포넌트에 호버할 때마다 랜덤 넘버가 변경된다!

그 이유는 바로 state가 변경될 때마다 컴포넌트가 재렌더링 되기 때문이다!
현재 RandomNum 컴포넌트에서는 isCloseBtnOpen이라는 state가 관리되고 있다. 마우스가 들어오고 나갈 때를 감지해, 우측 상단의 closeBtn의 렌더링 여부를 결정해주는 것이다!

// 이 함수가 매번 새롭게 실행됨!
const getRandomNum = (num) => {
  return Math.floor(Math.random() * num) + 1;
};

컴포넌트가 렌더링 된다는 것은 함수가 새롭게 호출되고 실행되는 것을 의미한다. 함수가 실행되면 당연하게도 내부에 선언된 표현식 변수나 함수 등도 매번 새로 선언되어 사용된다. 위에서 작성한 예시코드에서 역시 getRandomNum 함수가 매번 새롭게 실행되고, 랜덤 넘버가 변경되는 것이다. 그렇다면, 이런 고민이 들 수 있다!

내가 원할 때만 렌더링할 수는 없을까?

이 때 활용할 수 있는 것이 바로 useMemo이다.

위 코드펜에 작성한 코드에서 아래 부분만 수정을 하면, 더 이상 아까와 같은 버그가 발생하지 않는다! 컴포넌트에 마우스를 호버해도 랜덤넘버가 변경되지 않는 것을 알 수 있다.

// AS-IS
const randomNum = getRandomNum(maxNum);

// TO-BE
const randomNum = useMemo(() => getRandomNum(maxNum), [maxNum]);

useMemo와 useCallback의 차이점

사실 이미 위 코드펜 예시에 useCallback을 작성해놓았다. useMemo와 useCallback의 가장 큰 차이점은 useMemo는 특정 값을 반환하는 반면, useCallback은 함수를 반환한다는 것이다. 때문에 위 예시에서도 useMemo를 특정 값을 관리하는 randomNum 변수에 할당한 반면, useCallback을 통해 관리하는 것은 이벤트 핸들러에 해당하는 함수이다.

사실 아쉽게도 어떻게 useCallback을 직관적으로 눈에 보이게끔 이해할 수 있는지, 그 방법에 대해서는 아직 떠올리지 못했다. 모쪼록 useCallback을 통해 반환된 함수는 매번 새로 랜더링 되지 않는다고 하니, 그냥 우선은 그렇게 믿는 것으로...! 눈으로 확인할 더 좋은 방법, 혹은 실제 사용 사례 등은 계속해서 고민해봐야겠다.

profile
부정확한 정보나 잘못된 정보는 댓글로 알려주시면 빠르게 수정토록 하겠습니다, 감사합니다!

0개의 댓글