useMemouseCallback은 리렌더링 시 불필요한 계산과 함수 생성을 방지해서 성능을 최적화하는 데 사용돼.

TypeScript로 사용할 때는 반환 타입과 의존성 배열에 특히 신경 써야 해.


📘 예제 36: 계산된 값 캐싱 (useMemo)

import { useMemo, useState } from 'react';

const ExpensiveCalculation = () => {
  const [count, setCount] = useState(0);

  const double = useMemo<number>(() => {
    console.log('계산 중...');
    return count * 2;
  }, [count]); // count가 바뀔 때만 재계산됨

  return (
    <>
      <p>두 배: {double}</p>
      <button onClick={() => setCount(count + 1)}>증가</button>
    </>
  );
};

✅ useMemo<number>처럼 반환 타입을 명시할 수 있어. 복잡한 계산일수록 캐싱 효과가 커져.


📘 예제 37: 함수 메모이제이션 (useCallback)

import { useCallback, useState } from 'react';

const CallbackExample = () => {
  const [count, setCount] = useState(0);

  const handleClick = useCallback((): void => {
    alert(`현재 카운트: ${count}`);
  }, [count]);

  return <button onClick={handleClick}>알림</button>;
};

✅ useCallback은 함수를 메모이제이션해서, 불필요한 재생성을 방지해. 자식 컴포넌트에 함수를 prop으로 넘길 때 특히 중요해.


📘 예제 38: 의존성 배열 타입 이해

const [value, setValue] = useState(1);

const memoizedValue = useMemo(() => {
  return value * 10;
}, [value]); // ✅ value 타입은 number

// 잘못된 예: 의존성 빠뜨림
// useMemo(() => value * 10, []); ❌ value가 바뀌어도 캐시가 갱신되지 않음

✅ TypeScript는 의존성 배열을 정확히 분석하지 못하므로 ESLint의 react-hooks/exhaustive-deps 플러그인을 쓰는 것이 좋아.


📘 예제 39: 복잡한 객체 연산 캐싱

type User = {
  id: number;
  name: string;
};

const UserList = ({ users }: { users: User[] }) => {
  const sortedUsers = useMemo(() => {
    return [...users].sort((a, b) => a.name.localeCompare(b.name));
  }, [users]);

  return (
    <ul>
      {sortedUsers.map((user) => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
};

✅ useMemo는 정렬, 필터링 등 연산 비용이 큰 작업을 캐싱하는 데 유용해.

중요한 건 의존성 배열에 users처럼 정확한 참조를 넣는 것.