📌 React 렌더링 최적화: memo, useMemo, useCallback 완전정복하기
리액트로 프로젝트를 하다 보면 점점 컴포넌트가 많아지고,
어느 순간부터 불필요한 리렌더링이 자꾸 눈에 들어오기 시작했다.
처음엔 왜 느리지...? 싶었는데, 디버깅을 해보니
props는 안 바뀌었는데 자식 컴포넌트가 계속 리렌더링되고 있던 것.
그제야 React.memo, useMemo, useCallback 같은 최적화 도구들을 공부하게 됐다.
이번 글은 내가 공부하면서 정리한 내용을 바탕으로,
리액트에서 불필요한 렌더링을 줄이는 법과 Profiler로 성능을 분석하는 방법까지 정리해봤다.
🌀 함수형 컴포넌트 생명주기: useEffect로 다 해결된다!
클래스형 컴포넌트는 생명주기 메서드가 따로 있었지만,
함수형 컴포넌트에서는 useEffect 하나로 마운트, 업데이트, 언마운트를 모두 처리할 수 있다.
생명주기 | 클래스형 | 함수형 |
마운트 | componentDidMount() | useEffect(() => {}, []) |
업데이트 | componentDidUpdate() | useEffect(() => {}, [value]) |
언마운트 | componentWillUnmount() | useEffect(() => { return () => {...} }, []) |
이렇게 생명주기를 처리하면 렌더링 시점에 따른 동작 제어를 할 수 있다.
🧠 리렌더링 막는 핵심 최적화 함수 3가지
✅ 이미지 설명 삽입 위치
- useMemo: 함수 호출 결과를 저장
- useCallback: 함수 자체를 저장
- React.memo: 컴포넌트를 저장
📌 "재사용할 수 있는 건 재사용하자!"는 취지로 사용됨.
이미지에서 저장했다가 재사용하자!라는 문장이 이 흐름을 잘 표현해준다.
1️⃣ useMemo – 값 계산 결과를 기억하자
const result = useMemo(() => {
return heavyFunction(data);
}, [data]);
- 연산 비용이 큰 값을 메모이제이션함
- 의존성 배열([]) 안의 값이 바뀌지 않으면 계산하지 않음
- 예제: numberPlus1 = useMemo(() => plus1(number), [rerender])
2️⃣ useCallback – 함수를 기억하자
const handleClick = useCallback(() => {
console.log("클릭됨");
}, [count]);
- 리렌더링 시마다 함수를 새로 생성하는 걸 방지
- 자식 컴포넌트에 props로 넘기는 함수는 꼭 useCallback으로 감싸자
- 예제: plus1 = useCallback((num) => num + 1, [rerender])
3️⃣ React.memo – 컴포넌트를 기억하자
const MyComponent = memo(({ value }) => {
return <div>{value}</div>;
});
- props가 바뀌지 않으면 컴포넌트를 리렌더링하지 않음
- 무거운 컴포넌트, 자주 바뀌지 않는 컴포넌트에 유용
- 예제: NumberDisplay = memo(({ number }) => <div>{number}</div>)
🛠 React Developer Tools 설치 및 사용법
React 앱을 디버깅하고 성능 분석하기 위해 필수로 설치해야 하는 확장 프로그램이다.
설치 방법 (크롬 기준)
- Chrome 웹스토어에서 React Developer Tools 검색
- "Chrome에 추가" 클릭
- 크롬 개발자 도구(F12) → "⚛ Components" / "Profiler" 탭 생김
주요 기능
- Components 탭: 컴포넌트 구조, props, state 확인
- Hooks 상태 추적: 현재 상태가 어떻게 바뀌었는지 확인 가능
- Profiler 탭: 아래에서 자세히 설명!
🔍 Profiler로 성능 분석하기
Profiler란?
리액트 앱에서 어떤 컴포넌트가 얼마나 자주, 얼마나 오래 렌더링되는지 추적할 수 있는 도구.
사용법
- DevTools → Profiler 탭 클릭
- "Record" 버튼 클릭 → 앱에서 조작
- "Stop" 클릭 → 성능 분석 결과 확인
볼 수 있는 정보
- 렌더링 횟수
- 각 렌더링 소요 시간
- 리렌더링 원인 (props 변경, 부모 리렌더링 등)
예를 들어 App이 자주 리렌더링되는데 NumberDisplay가 props가 바뀌지 않아도 리렌더링된다면,
→ React.memo로 감싸서 최적화할 수 있다!
✅ 마무리
React는 기본적으로 빠른 프레임워크지만,
불필요한 리렌더링을 방지하지 않으면 성능 저하가 생길 수 있다.
📌 기억하자
- 복잡한 연산은 useMemo로 값 캐싱
- 함수는 useCallback으로 재생성 방지
- 컴포넌트는 React.memo로 리렌더링 차단
- 병목은 Profiler로 시각화하여 분석
이 4가지 도구를 적절히 조합하면
리액트 앱 성능을 체감할 수 있을 만큼 향상시킬 수 있다.