카테고리 없음

[React] useMemo (리액트 메모이제이션)

Jaka_Park 2024. 10. 3. 17:22

목차

1. useMemo 란?

2. useMemo 사용법

3. useMemo 사용 예제

4. 결론 및 요약

 

 

1. useMemo 란

useMemo는 리액트에서 사용하는 hook 중에 하나로 컴포넌트 성능을 최적화 해준다.

그럼 어떻게 컴포넌트의 성능을 최적화 해준다는 걸까? 좀 더 자세히 알아보자.

 

useMemo를 알기위해서는 memoization을 알아야한다. 메모이제이션을 검색하면 다음과 같이 정의가 나온다.

메모이제이션(memoization)은 컴퓨터 프로그램이 동일한 계산을 반복해야 할 때, 이전에 계산한 값을 메모리에 저장함으로써 동일한 계산의 반복 수행을 제거하여 프로그램 실행 속도를 빠르게 하는 기술이다. 동적 계획법의 핵심이 되는 기술이다.

- 나무위키 참고

메모이제이션을 이용하는 hook은 useMemo 말고도 useContext도 있다.

 

동일한 값을 반환하는 함수를 반복적으로 호출해야 할 때가 있다. 그럴때마다 함수를 호출하지 않고 계산할 때 해당 값을 메모리에 저장하고 필요할 때마다 다시 계산하지 않고 메모리에서 꺼내서 재사용 하는 것이 훨씬 효율적일 것이다. 이럴 때 메모이제이션을 사용한다.

 

- useMemo(메모이제이션)을 많이 쓰면 좋을까?

분명 방금 나는 useMemo(메모이제이션)을 최적화의 목적으로 사용한다고 말했다. 그렇다면 누군가는 이렇게 물업볼 것이다. 최적화하려고 사용한다고 하면 많이 쓰는게 좋은것이 아닐까? 하지만 그것은 틀린 말이다. 그 이유에 대해서는 나중에 다룰 일이 있으면 따로 포스팅할 예정이다.

 

2. useMemo 사용법

useMemo : 자주 쓰이는 값을 메모이제이션을 해준다. (캐싱해준다는 말이랑 같은 의미.) 그리고 값이 필요할 때 다시 계산을 하는 것이 아닌 useMemo를 통해 캐싱을 한 값을 메모리에서 꺼내와서 재사용한다. useMemo에 인자로 콜백함수를 넣어주면 함수가 리턴하는 값을 메모이제이션 하는 것이다. 

 

function Component(){
  const value = calculate();
  return <div>{value}</div>
}

function calculate(){
  return 10;
}

 

위에 함수를 확인해보자. 메모이제이션을 사용하지 않는다면 calculate 함수를 계속 호출해야하는 상황이 있을수 있다. 메모이제이션을 

컴포넌트가 계속 렌더링 되어도 calculate를  다시 호출하지 않고 메모리에 저장되어 있는 계산된 값을 가져와 재사용할 수 있게 해준다.

 

const value = useMemo(() => {
  return calculate();
}, [item]);

 

의존성 배열 안에 있는 값이 업데이트 될 때에만 콜백함수를 다시 호출하여 메모리에 저장된 값을 업데이트 해준다.

만약 빈 배열을 넣는다면 useEffect와 마찬가지로 마운트 될 때에만 값을 계산하고 그 이후론 계속 메모이제이션 된 값을 꺼내와 사용해야한다.

 

3. useMemo 사용 예제

import { useState, useEffect, useMemo } from 'react';

function App(){
  const [number, setNumber] = useState(0);
  const [isKorea, setIsKorea] = useState(true);

  // const location = { country: isKorea ? '한국' : '일본' };

  const location = useMemo(() => {
    return {
      country: isKorea ? '한국' : '일본'
    }
  }, [isKorea])

  useEffect(() => {
    console.log('useEffect 호출');
  }, [location]);

  return (
    <header className="App-header">
      <h2>하루에 몇 끼 먹어?</h2>
      <input type="number"
        value={number}
        onChange={(e) => setNumber(e.target.value)}
      />
      <hr />

      <h2>어느 나라에 있어요?</h2>
      <p>나라: {location.country}</p>
      <button onClick={() => setIsKorea(!isKorea)}>Update</button>
    </header>
  )
}

export default App;

 

4. 결론 및 요약

위에 함수는 useMemo를 사용한 것과 사용하지 않은 예제를 만들어 본 것이다.

useMemo를 사용한것과 사용하지 않은 것은 어떤 결과가 있을까?

결론부터 말하자면 useMemo를 사용하면 number의 상태가 변해도 useEffect의 console 이 찍히지 않는다.

그렇다면 useMemo를 사용하지 않는다면 숫자가 바뀔 때마다 console이 자꾸 찍힌다는 이야기인데 왜 그럴까?

 

useMemo를 사용하지 않는다면 number가 바뀔 때마다 새로 리렌더링이 된다. 리렌더링이 되는 과정에서 객체의 주소값이 바뀌게 된다. 그래서 주석으로 처리한 location을 사용할 경우 주소값이 바뀌기 때문에 location 객체로 의존성 배열을 할당받은 useEffect가 실행된다. 하지만 useMemo를 사용한다면 값을 기억하고 있는 메모이제이션을 사용하면 주소값이 바뀌는 것이 아니기 때문에 리렌더링을 하더라도 주소값이 바뀌지 않아 number를 바꿔도 useEffect가 살행되지 않는다.