Musta React

[✍🏼 1/4 (Sat)] useMemo() 복습

taytay 2025. 1. 4. 13:29

1️⃣ useMemo()의 역할

useMemo()는 값을 메모이제이션하기 위해 사용되는 React Hook입니다. 이로 인해 비용이 많이 드는 계산을 불필요하게 반복하지 않도록 최적화할 수 있습니다.

이 코드에서 useMemo()의 사용 목적은 아래와 같습니다:

  1. 컴포넌트 리렌더링 방지
    App 컴포넌트는 name 또는 num 상태값이 변경될 때마다 리렌더링됩니다.
    하지만 name이 변경되더라도, num이 바뀌지 않았다면 isPrime(num)을 다시 실행할 필요가 없습니다.
    👉 useMemo()를 사용하면, num이 변경되지 않은 경우 기존에 계산했던 결과를 재사용하게 됩니다.
  2. 비용이 큰 연산의 재사용
    isPrime() 함수는 주어진 숫자가 소수인지 확인하는 함수로, 숫자가 클수록 계산 비용이 커집니다.
    useMemo()는 num이 변경되지 않은 경우, 이전에 계산된 결과를 반환함으로써 불필요한 계산을 방지합니다.

 

2️⃣ Dependency Array ([num])의 역할

useMemo(() => isPrime(num), [num])에서 의존성 배열 [num]은 다음을 의미합니다:

  • num 값이 변경될 때만 isPrime(num)을 다시 실행합니다.
  • 만약 num이 바뀌지 않았다면, 이전에 계산된 값을 반환합니다.

전체 동작 과정

  1. 초기 상태
    컴포넌트가 처음 렌더링될 때 num 값은 1입니다.
    useMemo()는 isPrime(1)을 실행하고, 결과(false)를 result에 저장합니다.
  2. name이 변경될 때
    사용자가 name 입력값을 바꾸더라도 num 값이 변경되지 않았다면, isPrime()은 다시 실행되지 않습니다.
    👉 이전에 계산된 result 값이 그대로 사용됩니다.
  3. num이 변경될 때
    사용자가 num 값을 바꾸면, useMemo()는 isPrime(num)을 다시 실행합니다.
    새로운 결과를 result에 저장하고, 컴포넌트가 업데이트됩니다.

 

예시 상황

  1. 사용자가 name을 **"Alice"**로 바꿉니다.
    • isPrime()은 실행되지 않고, 기존의 result 값이 그대로 사용됩니다.
  2. 사용자가 num을 7로 변경합니다.
    • isPrime(7)이 실행되고, 결과(true)가 result에 저장됩니다.
    • 화면에 "Alice가 좋아하는 숫자 7: 소수가 맞습니다."가 표시됩니다.

 

useMemo()를 사용하지 않았다면?

만약 useMemo()를 사용하지 않았다면, App 컴포넌트가 리렌더링될 때마다(= name값만 변경되더라도) isPrime(num)이 항상 실행됩니다.
결과적으로 num 값이 바뀌지 않았더라도 불필요한 연산이 발생해 성능 저하를 초래할 수 있습니다.

 

 

결론

useMemo()를 사용함으로써:

  1. name이 변경될 때 불필요한 isPrime() 실행을 방지합니다.
  2. num이 변경될 때만 isPrime()을 실행해 효율적으로 컴포넌트를 업데이트합니다.
    이렇게 하면 성능 최적화와 계산 비용 절감을 동시에 달성할 수 있습니다.
import { useMemo, useState } from "react";

var isPrime = function (num) {
  console.time("소요 시간");
  console.log("소수 판별 시작.", num);

  // TODO: 소수 판별 코드
  let prime = num > 1; // 1은 소수가 아니기 때문에 거름.

  for (let i = 2; i < Math.sqrt(num); i++) {
    if (num % i === 0) {
      prime = false;
      break;
    }
  }

  console.log("소수 판별 결과.", prime);
  console.timeEnd("소요 시간");
  return prime;
};

function App() {
  const [name, setName] = useState("GD");
  const [num, setNum] = useState(1);

  // 📢 useMemo(): num값이 바뀌지 않으면 다시 계산하지 않고, 메모이제이션된 함수의 리턴값을 이용
  // -> 이름을 바꾸면 name이라는 상태값이 바뀌기 때문에 앱 컴포넌트 자체가 리렌더링 되어야 하는데, 이때 굳이 다시 계산하지 않음
  // * num(상태값)이 바뀌면 다시 계산할 필요o => dependency : [num]
  // const result = isPrime(num);
  const result = useMemo(() => isPrime(num), [num]);

  return (
    <>
      <h1>05 useMemo - 함수의 반환값을 memoize</h1>
      <div>
        <input
          type="text"
          value={name}
          onChange={(e) => setName(e.target.value)}
        />
        가 좋아하는 숫자:
        <input
          type="number"
          min="1"
          max="1000000007"
          value={num}
          onChange={(e) => setNum(e.target.value)}
        />
        <div>
          {name}가 좋아하는 숫자 {num}: 소수가
          {result ? (
            <span style={{ color: "blue" }}>맞습니다.</span>
          ) : (
            <span style={{ color: "red" }}>아닙니다.</span>
          )}
        </div>
      </div>
    </>
  );
}

export default App;