Development Study/Frontend

[React] useMemo 쓰지 마세요?

  • -
728x90

최근 useEffect 대응방안에서 useMemo를 사용해서 개선하는 방향과 관련된 글을 쓰다가 생각난 건데,
어떤 글에서 useMemo를 쓰지 말라는 주제로 글이 있던 것이 생각났습니다.

그래서 이참에 이것도 알아보기로 하였죠. 왜 useMemo를 쓰면 안 되는 건지,
그전에 useMemo는 무엇인지부터 알아보고 가도록 하겠습니다.

 

이전 글 보고오기

 

[React] 왜 React에서는 useEffect의 사용을 추천하지 않을까? - Side Effect 관리

React는 페이스북에서 개발한 강력한 프론트엔드 라이브러리 입니다. 상당히 많은 부분에서 useEffect 훅을 이용하여 개발을 진행하는데, React에서는 useEffect를 지양하고 있다고 합니다. 이번 글에서

time-map-installer.tistory.com

 


 

1. useMemo란 무엇인가?

useMemo는 React의 내장 Hook 중 하나로, 함수를 인자로 받아 그 함수의 메모이제이션된 반환 값을 제공합니다.

Hook은 주로 "비용이 많이 드는 연산"을 수행할 때 사용됩니다.

useMemo를 사용하여 계산 결과를 캐시하면, 해당 값이 변경되지 않는 한 컴포넌트가 다시 렌더링 될 때마다 값을 다시 계산하는 대신 이전에 계산된 값을 재사용할 수 있습니다.

 

메모이제이션?

메모이제이션은 이전에 계산한 결과를 저장해 두고, 동일한 입력이 주어졌을 때 다시 계산하는 대신 저장된 결과를 반환하는 기술입니다.

이를 통해 중복 계산을 피하고 실행 시간을 단축할 수 있습니다.

일반적으로 함수나 계산 결과를 메모이제이션하여 이후에 동일한 입력에 대해 다시 계산할 필요 없이 저장된 결과를 재사용할 수 있습니다.

React에서의 useMemo Hook은 메모이제이션을 구현하는 데 사용되며, 함수나 값의 결과를 캐시 하여 성능을 향상할 수 있습니다.

 

알고리즘 공부할 때 봤던 것 같기도 하고..?

맞습니다. 메모이제이션은 동적 계획법(Dynamic Programming)에서 흔히 사용되는 기술입니다.

동적 계획법은 문제를 작은 부분 문제(sub-problems)로 분할하고, 각 부분 문제의 결과를 저장하여 중복 계산을 피하는 최적화 기법입니다.

이때 메모이제이션은 부분 문제의 결과를 저장하고 필요할 때 재사용함으로써 중복 계산을 방지합니다.

이를 통해 동적 계획법 알고리즘의 실행 속도를 획기적으로 개선할 수 있습니다.

React의 useMemo Hook은 이와 유사한 개념을 사용하여 중복 계산을 피하고 성능을 최적화하는 데 활용됩니다.

 

비용이 많이 드는 연산?

비용이 많이 드는 연산은 주로 계산적으로 복잡하거나 시간이 많이 소요되는 작업을 말합니다. 

이러한 작업은 useMemo나 useRef를 사용하여 결과를 캐시함으로써 성능을 향상할 수 있습니다.

다양한 예시 중 일부를 살펴보겠습니다


1. 데이터 계산

대량의 데이터를 가공하거나 필터링하는 작업은 비용이 많이 드는 연산에 해당할 수 있습니다. 예를 들어, 수천 개의 항목을 정렬하거나 복잡한 계산을 수행하는 경우 useMemo를 사용하여 계산 결과를 캐시할 수 있습니다.

const sortedData = useMemo(() => {
  // 복잡한 정렬 알고리즘 또는 계산 로직
  return computeExpensiveSort(data);
}, [data]);


2. 외부 리소스 접근

외부 API 호출 또는 데이터베이스 쿼리와 같은 비동기 작업은 비용이 많이 드는 연산에 해당합니다.

이러한 작업의 결과를 useMemo를 사용하여 캐시하면, 동일한 요청이 여러 번 호출되는 것을 방지할 수 있습니다.

const data = useMemo(() => {
  const fetchData = async () => {
    // 외부 API 호출 또는 데이터베이스 쿼리
    const response = await fetchSomeData();
    return response.data;
  };

  return fetchData();
}, []);


3. 복잡한 계산

수학적인 계산이나 알고리즘 로직을 수행하는 경우에도 useMemo를 활용할 수 있습니다.

이를 통해 계산 결과를 캐시 하여 중복 계산을 피할 수 있습니다.

const result = useMemo(() => {
  // 복잡한 계산 로직
  return performComplexCalculation(a, b);
}, [a, b]);

이러한 예시들은 계산량이 많거나 시간이 오래 걸리는 작업에 적용될 수 있습니다.

useMemo를 사용하여 이러한 연산의 결과를 캐시 하면 성능을 향상할 수 있으며, 불필요한 재계산을 방지할 수 있습니다.

 

2. useMemo를 사용하는 상황은 언제일까?

useMemo의 주요 목적은 성능 최적화입니다. 

예를 들어, 특정 prop이 변경되었을 때만 연산을 수행해야 하는 상황에서 useMemo를 사용하면, 해당 prop이 변경되지 않았을 때는 이전에 계산된 값을 재사용하여 불필요한 계산을 피할 수 있습니다.

 

3. useMemo를 사용하면 안되는 이유는 무엇일까?

그러나 모든 상황에서 useMemo를 사용하는 것은 바람직하지 않습니다.

메모이제이션된 값이 비용이 적게 드는 계산이거나 컴포넌트가 언마운트되지 않는 한 계속 유지되어야 하는 값인 경우에는 useMemo를 사용하는 것이 적절하지 않을 수 있습니다.

또한, 원시값인 boolean이나 문자열과 같은 값에 대해서는 useMemo를 사용할 필요가 없습니다.

 

4. 그렇다면 어떤 방법을 사용해야 할까?

useMemo의 대안으로 useRef를 사용할 수 있습니다.

useRef는 값의 변경을 유지하기 위해 사용되는 Hook으로, useMemo와 유사한 역할을 수행할 수 있습니다.

useRef를 사용하여 값을 유지하면, 해당 값은 컴포넌트가 다시 렌더링되더라도 변경되지 않습니다.

 

useMemo와 같이 useRef를 사용하여 "비용이 많이 드는 연산"의 결과를 유지하고 싶은 경우에는 다음과 같이 사용할 수 있습니다

import { useRef } from 'react';

function ExampleComponent() {
  const expensiveValueRef = useRef(computeExpensiveValue());

  // ... 컴포넌트 내에서 expensiveValueRef를 사용하는 코드 ...

  return <div>...</div>;
}

위의 예시에서 computeExpensiveValue() 함수는 초기 렌더링 시에 한 번만 호출되고, 이후에는 해당 값이 변경되지 않습니다. useRef를 사용하여 이 값을 유지하면서 불필요한 재계산을 피할 수 있습니다.

useRef는 주로 DOM 노드의 참조를 유지하는 데에도 사용됩니다. 

이를 활용하여 인스턴스 변수를 모방하는 것도 가능합니다. 

useRef는 useMemo와 달리 값을 캐시하는 용도뿐만 아니라 DOM 노드 외에 다양한 상황에서 활용할 수 있는 기능을 제공합니다.

따라서 useMemo의 대안으로서 useRef를 사용하여 값을 유지하는 방법을 고려할 수 있습니다.

5. 결론

useMemo는 React에서 성능을 향상하기 위해 사용되는 Hook입니다.

비용이 많이 드는 연산의 결과를 캐시하여 중복 계산을 피하고 성능을 최적화하는 데 사용됩니다.

그러나 모든 상황에서 useMemo를 사용할 필요는 없으며, 작업이 간단하거나 비용이 적은 경우에는 메모리 사용과 성능 저하를 초래할 수 있습니다.

useMemo를 사용할 때는 신중하게 판단해야 합니다.

또한, useRef를 활용하여 값의 참조를 유지하거나 다른 성능 최적화 기법도 고려해야 합니다.

최적화 기법은 애플리케이션의 특성과 요구사항에 따라 다르므로 프로파일링과 성능 테스트를 통해 적절한 기법을 선택해야 합니다.


End

 

References

728x90
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.