[React] memo를 사용한 컴포넌트 최적화

2024. 12. 25. 18:45·TypeScript
반응형

소개

React의 memo 함수는 컴포넌트의 불필요한 리렌더링을 방지하여 성능을 최적화하는 데 사용됩니다. 이번 글에서는 memo의 올바른 사용법과 실제 사례를 살펴보겠습니다.

기본 사용법

import { memo } from 'react';

interface UserProfileProps {
  name: string;
  email: string;
}

const UserProfile = memo(function UserProfile({ name, email }: UserProfileProps) {
  return (
    <div className="user-profile">
      <h2>{name}</h2>
      <p>{email}</p>
    </div>
  );
});

export default UserProfile;

memo가 필요한 경우와 필요하지 않은 경우

memo가 유용한 경우

// 1. 큰 리스트의 항목 컴포넌트
const TodoItem = memo(function TodoItem({ todo, onToggle }: TodoItemProps) {
  return (
    <li>
      <input
        type="checkbox"
        checked={todo.completed}
        onChange={() => onToggle(todo.id)}
      />
      {todo.text}
    </li>
  );
});

// 2. 자주 변경되지 않는 데이터를 표시하는 컴포넌트
const StaticHeader = memo(function StaticHeader({ title }: HeaderProps) {
  return (
    <header>
      <h1>{title}</h1>
    </header>
  );
});

memo가 불필요한 경우

// 1. 자주 변경되는 데이터를 가진 컴포넌트
const Timer = () => {
  const [time, setTime] = useState(0);

  useEffect(() => {
    const interval = setInterval(() => setTime(t => t + 1), 1000);
    return () => clearInterval(interval);
  }, []);

  return <div>{time} seconds</div>;
};

// 2. 단순한 컴포넌트
const Button = ({ onClick, children }) => (
  <button onClick={onClick}>
    {children}
  </button>
);

커스텀 비교 함수 사용

const ExpensiveComponent = memo(
  function ExpensiveComponent({ data, onUpdate }: Props) {
    return (
      <div>
        {/* 복잡한 렌더링 로직 */}
      </div>
    );
  },
  (prevProps, nextProps) => {
    // 깊은 비교 수행
    return JSON.stringify(prevProps.data) === JSON.stringify(nextProps.data);
  }
);

성능 최적화 예제

리스트 최적화

interface ListProps {
  items: Item[];
  onItemClick: (id: string) => void;
}

const OptimizedList = memo(function OptimizedList({ 
  items, 
  onItemClick 
}: ListProps) {
  return (
    <ul>
      {items.map(item => (
        <ListItem
          key={item.id}
          item={item}
          onClick={onItemClick}
        />
      ))}
    </ul>
  );
});

const ListItem = memo(function ListItem({ 
  item, 
  onClick 
}: ListItemProps) {
  return (
    <li onClick={() => onClick(item.id)}>
      {item.name}
    </li>
  );
});

폼 컴포넌트 최적화

const FormField = memo(function FormField({
  label,
  value,
  onChange,
  error
}: FormFieldProps) {
  return (
    <div className="form-field">
      <label>{label}</label>
      <input value={value} onChange={onChange} />
      {error && <span className="error">{error}</span>}
    </div>
  );
});

// 사용 예시
const Form = () => {
  const [formData, setFormData] = useState({ name: '', email: '' });

  const handleNameChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
    setFormData(prev => ({ ...prev, name: e.target.value }));
  }, []);

  return (
    <form>
      <FormField
        label="Name"
        value={formData.name}
        onChange={handleNameChange}
      />
      {/* 다른 필드들 */}
    </form>
  );
};

memo와 다른 Hooks의 조합

useMemo와 함께 사용

const ComplexComponent = memo(function ComplexComponent({ 
  data,
  onProcess 
}: ComplexProps) {
  const processedData = useMemo(() => {
    return expensiveOperation(data);
  }, [data]);

  return (
    <div>
      {processedData.map(item => (
        <div key={item.id}>{item.value}</div>
      ))}
    </div>
  );
});

useCallback과 함께 사용

const ParentComponent = () => {
  const [items, setItems] = useState<string[]>([]);

  const handleAdd = useCallback((newItem: string) => {
    setItems(prev => [...prev, newItem]);
  }, []);

  return (
    <MemoizedChildComponent
      items={items}
      onAdd={handleAdd}
    />
  );
};

const MemoizedChildComponent = memo(function ChildComponent({
  items,
  onAdd
}: ChildProps) {
  return (
    <div>
      <button onClick={() => onAdd('new item')}>Add Item</button>
      <ul>
        {items.map(item => (
          <li key={item}>{item}</li>
        ))}
      </ul>
    </div>
  );
});

성능 측정

const withPerformanceLogging = <P extends object>(
  WrappedComponent: React.ComponentType<P>,
  componentName: string
) => {
  return memo(function LoggedComponent(props: P) {
    console.time(`${componentName} render`);
    const result = <WrappedComponent {...props} />;
    console.timeEnd(`${componentName} render`);
    return result;
  });
};

const OptimizedComponent = withPerformanceLogging(MyComponent, 'MyComponent');

주의사항

  1. 과도한 사용 피하기
  2. 올바른 의존성 관리
  3. 깊은 비교의 성능 영향 고려
  4. 컴포넌트의 책임 범위 명확히 하기

마치며

memo는 React 애플리케이션의 성능을 최적화하는 강력한 도구입니다. 하지만 모든 컴포넌트에 무분별하게 적용하는 것은 오히려 성능을 저하시킬 수 있으므로, 실제 성능 측정을 통해 필요한 곳에만 적용하는 것이 중요합니다.

저작자표시 비영리 변경금지 (새창열림)

'TypeScript' 카테고리의 다른 글

next.config.js 커스터마이징  (0) 2025.01.08
[React] React.lazy와 Suspense  (2) 2024.12.26
[React Query] useMutation과 useQuery  (0) 2024.12.24
[React] Zustand로 배우는 간단하고 강력한 상태 관리  (0) 2024.12.20
[React Query] QueryClient : 효율적인 상태관리와 데이터 캐싱  (0) 2024.12.19
'TypeScript' 카테고리의 다른 글
  • next.config.js 커스터마이징
  • [React] React.lazy와 Suspense
  • [React Query] useMutation과 useQuery
  • [React] Zustand로 배우는 간단하고 강력한 상태 관리
코샵
코샵
나의 코딩 일기장
    반응형
  • 코샵
    끄적끄적 코딩 공방
    코샵
    • 분류 전체보기 (544) N
      • 상품 추천 (54) N
      • MongoDB (4)
      • 하드웨어 (9)
      • 일기장 (4)
      • Unity (138)
        • Tip (41)
        • Project (1)
        • Design Pattern (8)
        • Firebase (6)
        • Asset (2)
      • 파이썬 (128) N
        • Basic (41) N
        • OpenCV (8)
        • Pandas (15)
        • PyQT (3)
        • SBC(Single Board Computer) (1)
        • 크롤링 (14)
        • Fast API (29)
        • Package (6)
      • Linux (4)
      • C# (97)
        • Algorithm (11)
        • Window (7)
      • TypeScript (39) N
        • CSS (10)
      • Git (11)
      • SQL (5)
      • Flutter (10)
        • Tip (1)
      • System (1)
      • BaekJoon (6)
      • Portfolio (2)
      • MacOS (1)
      • 유틸리티 (1)
      • 서비스 (6)
      • 자동화 (3)
      • Hobby (10)
        • 물생활 (10)
        • 식집사 (0)
  • 인기 글

  • 태그

    rtsp
    ipcamera
    믈레코비타멸균우유
    카페24리뷰이관
    스크립트 실행
    카페24리뷰
    cv2
    programmerlife
    라떼우유
    codingtips
    codingcommunity
    programming101
    유니티
    스마트스토어리뷰
    appdevelopment
    상품 리뷰 크롤링
    셀레니움
    unity
    devlife
    리뷰이관
    긴유통기한우유
    리스트
    리뷰관리
    파이썬
    스크립트 실행 순서
    list
    Python
    learntocode
    쇼핑몰리뷰
    C#
  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
코샵
[React] memo를 사용한 컴포넌트 최적화
상단으로

티스토리툴바