React 애플리케이션을 개발할 때 성능 최적화는 중요한 핵심 요소입니다. 렌더링 성능을 제대로 최적화하지 않으면 불필요한 리렌더링으로 인해 앱의 전반적인 반응성이 크게 저하될 수 있습니다. 이번 글에서는 TypeScript 기반으로 useMemo, useCallback, React.memo를 활용한 성능 최적화 방법을 상세히 알아보겠습니다.
💂♀️ React 성능 최적화가 필요한 이유
React는 상태(state)나 props가 변경될 때마다 컴포넌트를 자동으로 다시 렌더링합니다. 그러나 모든 렌더링이 실제로 필요한 것은 아닙니다. 불필요한 렌더링이 과도하게 발생하면 애플리케이션의 성능이 현저하게 저하될 수 있습니다. 이러한 문제를 예방하고 개선하기 위해 메모이제이션(memoization) 기법을 효과적으로 활용할 수 있습니다.
React에서 제공하는 최적화를 위한 hook
1. useMemo → 값을 메모이제이션하여 불필요한 연산 방지
2. useCallback → 함수를 메모이제이션하여 불필요한 함수 재생성 방지
3. React.memo → 컴포넌트를 메모이제이션하여 불필요한 리렌더링 방지
하나씩 예제를 살펴보겠습니다.
1. useMemo : State의 메모제이션
useMemo는 많이 소요되는 연산 결과를 저장하고, 의존성이 변경되지 않는다면 재계산하지 않도록 합니다.
즉, 불필요한 연산을 방지할 수 있습니다. 그러나 잘못 사용하게되면 오히려 오버헤드가 발생할 수도 있습니다.
import { useState, useMemo } from "react";
const ExpensiveComponent = () => {
const [count, setCount] = useState<number>(0);
const [text, setText] = useState<string>("");
// 연산 비용이 큰 작업 (ex: 배열의 합 구하기)
const expensiveValue = useMemo(() => {
console.log("expensiveValue 계산 중...");
return Array.from({ length: 10000 }, (_, i) => i).reduce((a, b) => a + b, 0);
}, []); // 의존성 배열이 빈 배열이므로 한 번만 계산됨
return (
<div>
<p>비싼 연산 결과: {expensiveValue}</p>
<button onClick={() => setCount(count + 1)}>Count 증가: {count}</button>
<input value={text} onChange={(e) => setText(e.target.value)} />
</div>
);
};
export default ExpensiveComponent;
2. useCallback: 함수의 메모제이션
useCallback은 함수의 재생성을 방지하여, 자식 컴포넌트에 전달할 때 불필요한 리렌더링을 막아줍니다.
자식 컴포넌트가 불필요하게 렌더링되지 않으나 확실히 의존성이 많아지면 코드가 점점 복잡해 질 수 있습니다.
import { useState, useCallback } from "react";
const ChildComponent = ({ onClick }: { onClick: () => void }) => {
console.log("ChildComponent 렌더링");
return <button onClick={onClick}>클릭</button>;
};
const ParentComponent = () => {
const [count, setCount] = useState<number>(0);
// useCallback을 사용하여 함수 재생성을 방지
const handleClick = useCallback(() => {
console.log("버튼 클릭!");
}, []);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>+1</button>
<ChildComponent onClick={handleClick} />
</div>
);
};
export default ParentComponent;
3. React.memo : 컴포넌트의 메모제이션
React.memo는 props가 변경되지 않는 한 컴포넌트를 다시 렌더링하지 않도록 합니다.
불필요한 리렌더링을 방지할 수 있지만 useMemo와 useCallback과 함께 사용해야하는 경우가 생기면 코드가 점점 복잡해집니다.
import React, { useState } from "react";
const MemoizedChild = React.memo(({ count }: { count: number }) => {
console.log("MemoizedChild 렌더링");
return <p>카운트 값: {count}</p>;
});
const ParentComponent = () => {
const [count, setCount] = useState<number>(0);
const [text, setText] = useState<string>("");
return (
<div>
<MemoizedChild count={count} />
<button onClick={() => setCount(count + 1)}>+1</button>
<input value={text} onChange={(e) => setText(e.target.value)} />
</div>
);
};
export default ParentComponent;
최적화의 중요성은 잘 알고 있지만 어떠한 상확에 적절하게 적용하는건 생각보다 어렵습니다. 모든 곳에 사용하지 말고 필요한 곳에 적절히 사용하는것이 중요해 보입니다. 😏
'React' 카테고리의 다른 글
| NextJS 에서 SEO 설정하기 (0) | 2025.03.31 |
|---|---|
| 요즘 대세인 react 전역 상태관리 jotai 와 zustand (0) | 2025.03.28 |
| 커스텀 hook 만들기 (0) | 2025.01.31 |
| 한글 초성 추출 하기 (7) | 2023.10.10 |
| React에서 clipboard에 copy&paste 하기 (0) | 2023.10.09 |