React useMemo로 성능 최적화를 해보자

성태팍·2024년 11월 21일
post-thumbnail

리액트에서 컴포넌트는 상태나 props가 변경될 때마다 리렌더링된다.
불필요한 계산이 반복되면 당연히 성능 저하가 발생한다.
useMemo는 이러한 문제를 해결하기 위해 제공되는 React의 Hook이다. 비용이 큰 계산을 메모이제이션(Memoization) 하여 성능을 최적화하는 것이다.

  const userLocale = useMemo(
    () => session.get(sessionCxt, "locale") || defaultLocale,
    [sessionCxt]
  );

1. useMemo의 기본 사용법

useMemo를 사용하지 않은 경우와 사용한 경우의 차이를 보자

1-1. useMemo를 사용하지 않은 경우

function Example({ a, b }) {
  const computeExpensiveValue = (a, b) => {
    console.log("비용이 큰 계산 실행");
    return a + b;
  };

  const result = computeExpensiveValue(a, b);

  return <div>결과: {result}</div>;
}

Example Component가 리렌더링 될 때마다 계산하는 함수가 실행 -> 비효율적!

1-2. useMemo를 사용한 경우

import React, { useMemo } from "react";

function Example({ a, b }) {
  const computeExpensiveValue = (a, b) => {
    console.log("비용이 큰 계산 실행");
    return a + b;
  };

  const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

  return <div>결과: {memoizedValue}</div>;
}

첫번째 인자는 콜백함수이고, 이 함수에서 리턴하는 값이 메모된다.
두번째 인자는 의존성 배열임

memoizedValue에 할당함으로써 a나 b가 변경되지 않는 한, computeExpensiveValue는 다시 실행되지 않음

2. 실무에서는?

2-1. 배열 데이터 필터링

큰 배열을 필터링 할 때 useMemo를 활용

import React, { useMemo } from "react";

function FilteredList({ items, searchTerm }) {
  const filteredItems = useMemo(() => {
    console.log("필터링 작업 실행");
    return items.filter(item => item.includes(searchTerm));
  }, [items, searchTerm]);

  return (
    <ul>
      {filteredItems.map(item => (
        <li key={item}>{item}</li>
      ))}
    </ul>
  );
}

2-2. 복잡한 계산

function ExpensiveCalculation({ number }) {
  const factorial = useMemo(() => {
    console.log("팩토리얼 계산 실행");
    const computeFactorial = n => (n <= 1 ? 1 : n * computeFactorial(n - 1));
    return computeFactorial(number);
  }, [number]);

  return <div>팩토리얼: {factorial}</div>;
}

2-3. 데이터 테이블 정렬

function SortedTable({ data, sortKey }) {
  const sortedData = useMemo(() => {
    console.log("데이터 정렬 실행");
    return [...data].sort((a, b) => a[sortKey].localeCompare(b[sortKey]));
  }, [data, sortKey]);

  return (
    <table>
      <tbody>
        {sortedData.map(row => (
          <tr key={row.id}>
            <td>{row.name}</td>
          </tr>
        ))}
      </tbody>
    </table>
  );
}

3. 주의사항

  • 최적화 시켜준다고 무작정 사용해서는 안됨! 정말 자주 변경이 이루어지는 처리에서만 활용하면 효율이 좋다.

  • 반복문이나 조건문 내부에서는 호출할 수 없다.

  • 새로운 데이터를 만들 때 그다지 복잡하지 않다면 메모이제이션 하는 비용보다 그냥 새로운 값을 만들어주는게 나을 수 있다.

profile
안녕하세요. 반갑습니다. 건강하세요.

0개의 댓글