useCallback과 useMemo 기초
useCallback과 useMemo는 React의 성능 최적화를 위한 훅으로, 각각 함수와 값의 메모이제이션을 제공합니다.
이 훅들을 적절히 사용하면 불필요한 리렌더링을 방지하고 애플리케이션의 성능을 향상시킬 수 있습니다.
useCallback
useCallback은 콜백 함수를 메모이제이션하는 데 사용됩니다.
이는 불필요한 리렌더링을 방지하고 자식 컴포넌트에 안정적인 함수 참조를 전달하는 데 유용합니다.
기본 사용법
이 예제에서 handleClick
함수는 컴포넌트가 리렌더링되어도 새로 생성되지 않습니다.
useMemo
useMemo는 계산 비용이 큰 값을 메모이제이션하는 데 사용됩니다.
이는 불필요한 재계산을 방지하여 성능을 최적화합니다.
기본 사용법
이 예제에서 expensiveResult
는 list
가 변경될 때만 재계산됩니다.
useCallback과 useMemo의 차이점
- useCallback은 함수 자체를 메모이제이션합니다.
- useMemo는 함수의 결과 값을 메모이제이션합니다.
의존성 배열의 역할
의존성 배열은 메모이제이션된 값이나 함수가 언제 재생성되어야 하는지를 React에게 알려줍니다.
- 빈 배열(
[]
)은 컴포넌트가 마운트될 때만 함수나 값을 생성합니다. - 의존성이 포함된 배열(
[dep1, dep2]
)은 해당 의존성이 변경될 때마다 함수나 값을 재생성합니다. - 배열이 없으면 매 렌더링마다 함수나 값이 재생성됩니다.
적절한 사용 상황
useCallback
- 자식 컴포넌트에 함수를 prop으로 전달할 때
- useEffect의 의존성 배열에 함수를 포함시킬 때
useMemo
- 계산 비용이 큰 연산을 수행할 때
- 객체를 생성하여 자식 컴포넌트에 전달할 때
성능 최적화 전략
- 선택적 사용 : 모든 함수나 값에 useCallback과 useMemo를 적용하는 것은 오히려 성능을 저하시킬 수 있습니다. 실제로 성능 향상이 필요한 부분에만 적용하세요.
- 의존성 배열 최적화 : 의존성 배열에는 필요한 값만 포함시켜 불필요한 재생성을 방지하세요.
- 컴포넌트 분할 : 큰 컴포넌트를 작은 단위로 분할하여 리렌더링 범위를 줄이는 것도 좋은 전략입니다.
- React.memo와 함께 사용 : useCallback과 useMemo는 React.memo와 함께 사용할 때 더 효과적입니다.
과도한 사용의 위험성
- 코드 복잡성 증가 : 과도한 사용은 코드를 더 복잡하게 만들고 가독성을 떨어뜨릴 수 있습니다.
- 성능 오버헤드 : 메모이제이션 자체도 비용이 들기 때문에, 단순한 연산이나 함수에 적용하면 오히려 성능이 저하될 수 있습니다.
- 버그 발생 가능성 의존성 배열을 잘못 관리하면 예상치 못한 버그가 발생할 수 있습니다.
성능에 미치는 영향
useCallback과 useMemo는 메모리 사용량을 증가시키는 대신 CPU 사용량을 줄이는 트레이드오프를 제공합니다.
따라서 사용 시 다음 사항을 고려해야 합니다.
- 측정 가능한 성능 향상 : 실제로 성능 향상이 있는지 React DevTools Profiler 등을 사용하여 측정하세요.
- 렌더링 빈도 : 자주 리렌더링되는 컴포넌트에서 더 효과적입니다.
- 계산 복잡도 : 복잡한 계산이나 큰 객체를 다룰 때 더 유용합니다.
useCallback과 useMemo는 React 애플리케이션의 성능을 최적화하는 강력한 도구입니다. 그러나 이들의 효과적인 사용을 위해서는 애플리케이션의 특성과 성능 병목 지점을 정확히 파악해야 합니다. 무분별한 사용은 오히려 성능 저하와 코드 복잡성 증가를 초래할 수 있으므로, 항상 측정 가능한 성능 문제에 대한 해결책으로 접근해야 합니다.
또한, 이러한 최적화 기법들은 React의 Concurrent Mode와 같은 미래의 기능들과 잘 작동하도록 설계되었습니다. 따라서 적절히 사용된 useCallback과 useMemo는 현재의 성능 최적화뿐만 아니라 미래의 React 기능들과의 호환성도 보장할 수 있습니다.