React 애플리케이션이 커질수록 상태 관리와 렌더링 성능 관리가 중요해진다. 이번 글에서는 다음 개념들을 정리해보려고 한다.
- useReducer
- useMemo
- React.memo
- useCallback
이 개념들은 복잡한 상태 관리와 불필요한 렌더링을 줄이기 위한 핵심 도구들이다.
1️⃣ useReducer
useReducer는 React에서 상태(state)를 관리하기 위한 Hook이다. 기본적으로는 useState와 같은 역할을 하지만, 복잡한 상태 로직을 컴포넌트 밖으로 분리할 수 있다는 특징이 있다.
1. useState의 문제점
상태가 많아질수록 컴포넌트 내부가 복잡해진다.
const [count, setCount] = useState(0);
const increase = () => {
setCount(count + 1);
};
const decrease = () => {
setCount(count - 1);
};
로직이 많아지면 컴포넌트 내부 코드가 길어지고 관리가 어려워진다.
2. useReducer 구조
useReducer는 Reducer 함수와 action을 이용해 상태를 관리한다.
const [state, dispatch] = useReducer(reducer, initialState);
구성 요소
- state : 현재 상태
- dispatch : 상태 변경 요청 함수
- reducer : 상태 변경 로직
- initialState : 초기 상태
import { useReducer } from "react";
function reducer(state, action) {
switch (action.type) {
case "INCREASE":
return { count: state.count + 1 };
case "DECREASE":
return { count: state.count - 1 };
default:
return state;
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, { count: 0 });
return (
<div>
<p>{state.count}</p>
<button onClick={() => dispatch({ type: "INCREASE" })}>
증가
</button>
<button onClick={() => dispatch({ type: "DECREASE" })}>
감소
</button>
</div>
);
}
동작 방식
① 버튼 클릭
② dispatch 실행
③ reducer가 action.type 확인
④ 새로운 state 반환
⑤ 컴포넌트 리렌더링
3. useState vs useReducer
| useState | useReducer |
| 간단한 상태 관리 | 복잡한 상태 관리 |
| 로직이 컴포넌트 내부에 있음 | 상태 로직을 외부로 분리 가능 |
| 작은 프로젝트에 적합 | 상태가 많거나 로직이 복잡할 때 적합 |
2️⃣ React 성능 최적화
React에서 렌더링이 많이 발생하면 성능 문제가 생길 수 있다. 대표적인 최적화 방법은 다음과 같다.
- useMemo
- React.memo
- useCallback
3️⃣ useMemo
useMemo는 연산 결과를 메모이제이션해서 불필요한 계산을 방지하는 Hook이다.
메모이제이션이란?
같은 연산을 반복할 때 이전에 계산한 결과를 재사용하는 기법이다.
import { useMemo } from "react";
function App({ number }) {
const expensiveValue = useMemo(() => {
console.log("비싼 연산 실행");
return number * 1000;
}, [number]);
return <div>{expensiveValue}</div>;
}
- number가 변경될 때만 연산 실행
- 동일한 값이면 이전 결과 재사용
4️⃣ React.memo
React.memo는 컴포넌트 자체를 메모이제이션하는 기능이다. 부모 컴포넌트가 리렌더링 되더라도 props가 바뀌지 않으면 자식 컴포넌트는 렌더링 되지 않는다.
import React, { memo } from "react";
const Child = memo(({ value }) => {
console.log("Child 렌더링");
return <div>{value}</div>;
});
export default Child;
<Child onClick={() => console.log("click")} />
이 경우 부모가 리렌더링 될 때마다 새로운 함수가 생성되기 때문에 Child도 리렌더링 된다.
5️⃣ useCallback
이 문제를 해결하기 위해 useCallback을 사용한다. useCallback은 함수를 메모이제이션하는 Hook이다.
import { useCallback } from "react";
function App() {
const handleClick = useCallback(() => {
console.log("클릭");
}, []);
return <Child onClick={handleClick} />;
}
useMemo vs useCallback
| Hook | 역할 |
| useMemo | 값 메모이제이션 |
| useCallback | 함수 메모이제이션 |
useMemo(() => value, [])
useCallback(() => {}, [])
React 최적화의 기본 원칙
기능 구현 -> 필요할 때 최적화
무조건 useMemo, useCallback을 사용하는 것은 오히려 코드 복잡도를 높일 수 있다. 그래서 실제로는 성능 문제가 발생하는 경우에만 적용하는 것이 좋다.
정리
React에서 성능 최적화와 상태 관리를 위해 다음 Hook들을 사용할 수 있다.
- useReducer : 복잡한 상태 관리
- useMemo : 값 메모이제이션
- React.memo : 컴포넌트 렌더링 최적화
- useCallback : 함수 메모이제이션
이러한 도구들을 활용하면 불필요한 연산과 렌더링을 줄여 React 애플리케이션의 성능을 개선할 수 있다.
'💻 STUDY > Frontend' 카테고리의 다른 글
| React 렌더링 최적화에 대해서 (0) | 2026.04.15 |
|---|---|
| React 렌더링 원리와 Virtual DOM (0) | 2026.03.13 |
| 라이프사이클과 useEffect (0) | 2026.03.13 |
| Props의 전달 (0) | 2026.03.12 |
| State 정리 (0) | 2026.03.11 |