useMemo
는 컴포넌트 리렌더링 간에 계산 결과를 캐싱할 수 있는 Hook(훅)이다.
그래서 성능상의 이유로만 사용되며, useCallback, 디바운싱, 동시 렌더링 등과 같은 기술과 함께 사용해야 한다. 이 훅은 일부 상황에서는 굉장히 도움이 되지만, 대부분의 개발자가 적절하게 사용하지 못하고 있다.
메모이제이션(memoization)은 대가 없이 제공되지 않는다.
하지만 그들은 최적화가 되기를 바라며, 모든 변수를 useMemo로 감싼다. 이 방법은 그저 가독성이 떨어지고 메모리 사용량을 증가할 뿐이다.
메모이제이션, 개념만 보았을 때는 굉장히 효율적이고 사용하기만 하면 최적화가 이루어질 것 같은 느낌이 들기도 합니다. 하지만 명확한 목적없이 무작정 메모이제이션을 사용하는 것은 오히려 비효율적입니다.
새로운 값을 만드는 것
과어딘가에 이전의 값을 저장해두고 메모이제이션 함수를 호출하고 의존성을 비교해서 가져올지 말지 여부를 판단하는 것
중 어떤 것이 비용이 더 적게 들까?
위의 문장에 대한 정답은 상황에 따라 다릅니다.
만약 새로운 값을 만드는 과정이 복잡하다면 메모이제이션을 사용하는 것이 더 효율적일 수 있습니다. 하지만 새로운 값을 만드는 과정이 복잡하지 않다면 메모이제이션을 사용하는 것은 오히려 비용이 더 많이 들수도 있습니다. 컴퓨터 자원의 측면뿐만 아니라 메모이제이션을 쓰면서 코드의 복잡도가 올라간다는 개발적인 측면의 비용도 무시할 수 없습니다.
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
useMemo
는 두가지 인자를 받습니다.
메모이제이션을 할 때 주의해야 할 점은 만약 새로운 값을 만들어서 사용해야 하는 상황임에도 불구하고 이전의 결과를 그대로 활용해버리면 버그가 발생할 수 있다는 점입니다.
위의 예시에서 a, b
라는 두가지 변수를 이용해서 메모이제이션 하기 위한 값을 계산하고 있습니다. 그런데 만약 a, b
라는 값이 변경되었는데 이전의 값을 그대로 활용해버리면 의도한 결과와 다른 결과가 나오게 될 것입니다.
이런 상황을 방지하기 위해서 useMemo
에서는 의존성 배열을 인자로 받아, 의존성 배열에 있는 값 중 하나라도 이전 렌더링과 비교했을 때 변경되었다면 메모된 값을 활용하는 것이 아니라 새로운 값을 다시 계산합니다.