리액트에서 메모이제이션과 메모이제이션으로 사용되는 훅중 useMemo와 고차컴포넌트에 대해 알아보도록 하겠습니다.
📑목차
1. 메모이제이션
1-1. 메모이제이션이란?
1-2. 왜 메모이제이션이 필요한가?
1-3. 렌더링과 불필요 리렌더 개념 정리
2. memo
2-1. memo 란?
2-2. memo 문법
3. useMemo
3-1. useMemo란?
3-2. useMemo 문법
3-3. useMemo를 언제사용할까?
4. React.memo VS useMemo
4-1. 이 둘의 차이점
5. HOC
5-1. HOC란?
5-2. HOC 특징
서론
현대 React 애플리케이션에서 퍼포먼스 최적화의 핵심은 “불필요한 리렌더를 얼마나 줄이느냐”에 달려 있습니다. 이 글은 그 출발점인 메모이제이션의 개념을 정리하고, React가 얕은 비교와 참조 동일성을 통해 렌더링 여부를 판단하는 방식을 짚은 뒤, 컴포넌트 단위의 캐싱을 제공하는 React.memo와 값 계산을 캐싱하는 useMemo의 문법과 동작 원리를 비교합니다. 더 나아가 두 도구의 차이와 올바른 사용 시점, 남용 시 발생할 수 있는 비용과 함정까지 살펴보며, 패턴 관점에서의 HOC(High-Order Component) 개념과 특징도 함께 정리합니다. 목표는 “언제, 무엇을, 왜” 메모이제이션할지에 대한 실전 감각을 제공해, 읽고 난 뒤에는 불필요한 리렌더를 스스로 진단 및 개선할 수 있도록 돕는 것입니다.
본론
1. 메모이제이션
1-1. 메모이제이션이란?
프로그래밍에서 같은 입력이면 같은 결과인 계산의 결과를 저장해 두었다가, 다음에 동일한 입력이 오면 재계산 없이 즉시 반환하는 애플리케이션 최적화 기법을 뜻한다
1-2. 메모이제이션이 왜 필요할까?
동일한 계산을 반복해야 할 때 메모이제이션 기법을 사용하는데, 이전에 계산한 값을 메모리에 저장함으로써 불필요한 재계산을 하지 않도록 하여 렌더링 속도를 높이고, 전반적인 애플리케이션 성능을 최적화하기 때문이다.
1-3. 렌더링과 불필요한 리렌더링 개념
렌더링은 애플리케이션의 상태(state)나 속성(props)이 변경될 때, 그 변화를 반영하여 UI를 다시 그려주는 과정을 말합니다. 그럼 불필요한 리렌더링이란 UI 결과가 실질적으로 바뀌지 않는데도 발생하는 리렌더링을 말합니다.
function Parent() {
const [count, setCount] = useState(0);
return (
<>
<button onClick={() => setCount(count + 1)}>+</button>
<Child />
</>
);
}
function Child() {
console.log("자식 리렌더!");
return <div>나는 변하지 않아요</div>;
}
예를 들면 여기서 Child는 상태도 없고 전달받을 데이터도 안 받는데, 부모가 리렌더될 때마다 같이 리렌더링 됩니다. 이런경우가 불필요한 리렌더링이라고 볼 수 있습니다.
2. memo
2-1. memo란?
불필요한 리렌더링을 방지하기 위한 고차 컴포넌트(HOC)를 말합니다
2-2. memo 문법
import React, { memo } from 'react'
// memo를 사용한 컴포넌트의 리렌더링 조건
// 1) props 값이 바뀌었을 때 (shallow compare 기준)
// 2) 본인의 state가 바뀌었을 때
// 3) 부모가 리렌더되더라도 props가 변하지 않으면 memo로 감싼 자식은 리렌더되지 않음
// ※ memo는 HOC(고차 컴포넌트) 방식으로 동작
const Child = memo(({ count, name }) => {
console.log(`${name} 나 렌더링이 되었어`);
return (
<div>
{count}
</div>
)
})
export default Child
React.memo는 props 변화를 얕은 비교로 감지하여, 값이 동일하면 이전 결과를 재사용하고 값이 달라지면 새롭게 렌더링하는 고차 컴포넌트(HOC)입니다. 내부 state가 바뀌면 항상 리렌더링이 발생합니다. 따라서 Child는 부모가 리렌더되더라도 count나 name이 바뀌지 않으면 새로 렌더링되지 않습니다.
3. useMemo
3-1. useMemo란?
성능 최적화중 리액트에서 제공하는 훅으로, 메모이제이션하기 위해 사용된다
3-2. useMemo 문법
const memoizedValue = useMemo(() => {
// 계산할 코드
return 값;
}, [의존성 배열]);
useMemo에 문법을 간단하게 살펴보자면 첫 번째 인자로는 콜백 함수를, 두 번째 인자로는 의존성 배열을 받습니다.
첫 번째 인자인 콜백 함수는 메모이제이션을 하기 위한 값을 반환하는 값을 말합니다. 즉 useMemo가 반환하는 값을 말하는거죠, 두 번째 인자로는 의존성 배열을 받는데 여기서 의존성 배열의 값이 변화할때 메모이제이션을 합니다. 빈 배열을 의존성 배열로 전달하는 경우, 컴포넌트가 처음 마운트될 때 단 한 번만 메모이제이션이 수행되고, 그 이후에는 재계산되지 않습니다.
3-3. useMemo를 언제 사용할까?
useMemo는 컴포넌트가 렌더링될 때마다 매번 반복되는 비용이 큰 연산을 최적화하기 위해 사용합니다. 예를 들어 검색, 필터링, 정렬, 복잡한 계산 같은 작업을 매번 새로 수행하지 않고, 의존성 배열에 포함된 값이 변경될 때만 다시 계산하여 결과를 메모이제이션합니다. 이렇게 하면 불필요한 재계산을 줄이고 성능을 개선할 수 있으며, 특히 큰 리스트 처리나 객체 및 배열 참조 안정성이 필요한 상황에서 효과적입니다. 다만 연산이 가벼운 경우에는 useMemo를 사용하지 않아도 되며, 꼭 필요한 경우에만 선택적으로 적용하는 것이 좋습니다.
4. React.memo VS useMemo
4-1. 이 둘의 차이점
먼저 React.memo는 고차 컴포넌트입니다. 이 말은 즉 새로운 컴포넌트를 반환받는 컴포넌트를 말하는 겁니다. 클래스형 컴포넌트이든, 함수형 컴포넌트이든 결과론적으로는 리액트 컴포넌트라는 겁니다. 함수형, 클래스형에서 사용할 수 있다는 점입니다. 또한 React.memo는 props 변화가 없을때 리렌더링을 방지하는 용도로 사용됩니다. 그럼 useMemo랑은 무엇이 다를까요?
React.memo와 useMemo 공통점으로는 메모이제이션 즉 , "이전 상태 값과 새로운 값이 동일하다면, 인자로 넘긴 함수(또는 계산)를 다시 실행하지 않고 이전에 캐싱된 결과를 재사용" 한다는 것입니다. 차이점으로는 useMemo는 훅이기 때문에 함수형 컴포넌트에서만 동작할 수 있습니다. 또한 memo는 컴포넌트가 리렌더링을 막기위해 사용되고, useMemo는 값을 계산하기 위한 용도로 사용되는 차이점이 있습니다.
useMemo가 함수형 컴포넌트에서만 동작하는 이유는 훅(Hook)은 함수형 컴포넌트에서만 동작하는 이유는, 훅이 함수 실행 순서를 기반으로 상태와 생명주기를 관리하는 메커니즘으로 설계되었기 때문입니다. React는 함수형 컴포넌트가 렌더링될 때 useState, useEffect 같은 훅들이 호출되는 순서를 기억하고, 그 순서에 맞게 상태를 매칭해 관리합니다. 그래서 훅은 항상 같은 순서로 호출되어야 하고, 반복문이나 조건문 안에서 훅을 사용할 수 없는 규칙이 생긴 것이죠. 반면 클래스형 컴포넌트는 this.state와 setState, 그리고 componentDidMount, componentDidUpdate 같은 생명주기 메서드를 통해 상태와 사이드이펙트를 다루기 때문에 구조가 전혀 다릅니다. 즉, 클래스형은 this 기반이고, 함수형은 "호출 순서 기반" 이기 때문에 훅을 클래스형 컴포넌트에 적용할 수 없습니다. 따라서 훅은 함수형 컴포넌트에서도 상태 관리와 생명주기 로직을 활용할 수 있게 하려는 목적으로 도입되었고, 그 동작 원리상 함수형 컴포넌트에서만 사용할 있게 된 것입니다.
5. HOC (High-Order-Component)
5-1. HOC란?
컴포넌트를 인자로 받아서 새로운 컴포넌트를 반환하는 함수
5-2. HOC 특징
- 원본 컴포넌트를 수정하지 않고 감싼다
HOC는 기존 컴포넌트를 직접 변경하지 않고, 감싸서 새로운 기능을 추가하기 때문에 원본 컴포넌트의 순수성을 유지합니다. - 재사용 가능한 로직을 분리할 수 있다
여러 컴포넌트에서 공통으로 사용되는 로직을 HOC로 분리하면 코드의 중복을 줄이고 재사용성을 높일 수 있습니다. - 순수 함수처럼 동작한다
HOC는 입력(컴포넌트)을 받아 출력(새로운 컴포넌트)을 반환하는 함수형 패턴이므로, 같은 입력에는 항상 같은 출력이 나오는 순수 함수와 유사하게 동작합니다. - 관심사 분리에 유용하다
UI를 담당하는 컴포넌트와 로직을 담당하는 HOC를 분리할 수 있어, 코드 구조를 깔끔하고 유지보수하기 쉽게 만듭니다.
결론
메모이제이션은 동일한 계산 결과를 메모리에 저장해 불필요한 재계산을 방지하는 최적화 기법입니다. 이를 통해 렌더링 지연을 줄이고 애플리케이션 성능을 향상시킬 수 있습니다. React에서는 이 개념을 활용해 불필요한 연산과 리렌더링을 줄이는 데 사용됩니다. HOC는 기존 컴포넌트를 수정하지 않고 감싸서 새로운 기능을 부여하는 패턴입니다. 이를 통해 공통 로직을 재사용하고, UI와 로직을 분리해 유지보수를 쉽게 할 수 있습니다. 따라서 HOC는 재사용성과 관심사 분리에 유용한 React 패턴이라고 할 수 있습니다.
'React 기록' 카테고리의 다른 글
| 리액트 useCallback이란? (4) | 2025.08.21 |
|---|---|
| 리액트 Context와 useContext 훅이란? (0) | 2025.05.11 |
| 리액트 커스텀 훅(Custom Hooks)이란? (0) | 2025.05.11 |
| 리액트 redux-thunk를 사용한 비동기 처리 (0) | 2025.05.09 |
| 리액트 리덕스(redux)란? (2) | 2025.05.08 |