React
React 기본 상태관리 hook 및 다양한 라이브러리 정리
해보구
2025. 6. 22. 23:33
React 상태관리 훅 & 라이브러리 완전 정리
1. React의 기본 상태관리 훅
Hook | 설명 | 주요 용도 | 코드 예시 |
---|---|---|---|
useState |
컴포넌트 내부에서 상태를 선언하고 관리하는 가장 기본적인 훅. [상태값, 상태변경함수] 쌍으로 반환. 여러 개의 상태를 독립적으로 선언 가능. |
간단한 UI 상태, 입력값, 토글 등 |
const [count, setCount] = useState(0);
|
useReducer |
복잡한 상태 로직이나 여러 상태값을 한 곳에서 관리할 때 사용하는 훅. Redux 스타일의 상태 관리를 함수형 컴포넌트에서 구현. |
폼 상태, 복합 상태 로직 |
function reducer(state, action) {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
default:
return state;
}
}
const [state, dispatch] = useReducer(reducer, { count: 0 });
|
useContext |
컴포넌트 트리 전체에 데이터를 전역적으로 공급. props drilling 없이 하위 컴포넌트에서 값 접근 가능. |
전역 테마, 로그인 정보, 언어 등 |
const value = useContext(MyContext);
|
useEffect |
컴포넌트가 렌더링된 후 side effect 처리(데이터 요청, 구독, DOM조작 등). 의존성 배열로 실행 시점 제어. |
API 호출, 이벤트 등록, 타이머 등 |
useEffect(() => { /* side effect */ }, [deps]);
|
2. React 성능 최적화 훅/기법
Hook/기법 | 설명 | 적용 예시 | 코드 예시 |
---|---|---|---|
useMemo |
복잡한 연산 결과를 메모이제이션하여 동일 입력 시 재계산 방지. 의존성 배열 값이 바뀔 때만 연산 수행. |
대용량 데이터 정렬, 합계 등 파생 데이터 생성 |
const total = useMemo(() => items.reduce((acc, item) => acc + item.price, 0), [items]);
|
useCallback |
함수 객체를 메모이제이션하여 불필요한 자식 리렌더링 방지. 의존성 배열 값이 바뀔 때만 새 함수 생성. |
자식 컴포넌트에 콜백 전달 시 |
const handleClick = useCallback(() => setCount(c => c + 1), []);
|
React.memo |
props가 바뀌지 않으면 컴포넌트 리렌더링 차단. 순수 컴포넌트에 최적화. |
리스트 아이템, UI 조각 등 |
const MemoizedComponent = React.memo(MyComponent);
|
Suspense |
비동기 로딩 중 폴백 UI 제공. 코드 분할(React.lazy), 데이터 페칭 등에서 활용. |
React.lazy, 서버 데이터 로딩 |
<Suspense fallback=<Spinner />>
<LazyComponent /> </Suspense> |
커스텀 훅 |
반복되는 상태관리/로직을 재사용 가능한 훅으로 분리. 여러 컴포넌트에서 공통 로직 공유. |
API 호출, 폼 입력 등 공통 로직 |
function useFetch(url) {
const [data, setData] = useState(null); useEffect(() => { fetch(url).then(res => res.json()).then(setData); }, [url]); return data; } |
3. 전역 상태관리 라이브러리
라이브러리 | 특징 | 주요 사용처 |
---|---|---|
Redux |
단일 스토어, 액션-리듀서 구조, 예측 가능한 단방향 데이터 흐름. 복잡한 전역 상태, 대규모 프로젝트에 적합. |
대규모 앱, 복잡한 전역 상태 |
Redux Toolkit |
Redux 공식 툴킷, 보일러플레이트 감소, 비동기/슬라이스 관리 강화. createSlice, createAsyncThunk, extraReducers 등 제공. |
Redux의 현대적 사용법 |
Recoil |
atom 단위의 유연한 상태 관리, React 친화적. 전역/부분 상태를 동적으로 관리. |
부분 전역/로컬 상태, 동적 상태 |
Zustand |
가볍고 간단한 함수형 스토어, 러닝커브 낮음. 빠른 전역 상태 관리에 적합. |
중소규모 앱, 빠른 전역 상태 |
Context API |
React 내장 전역 상태, props drilling 방지. 규모가 크면 성능 저하 가능. |
테마, 인증 등 단순 상태 공유 |
React Query |
서버 상태(캐시) 전역 관리, 비동기 데이터 자동 동기화. useQuery, useMutation 등 제공. |
API 데이터, 서버 상태 관리 |
4. Redux Toolkit의 extraReducers란?
extraReducers는 createSlice 내부에서 외부 액션(다른 slice, createAsyncThunk 등)에 반응하여 상태를 업데이트할 때 사용합니다.
예시: 비동기 API 처리, 여러 슬라이스가 동일 액션에 반응해야 할 때 등.
reducers는 해당 slice에서 만든 액션만 처리, extraReducers는 외부 액션도 처리 가능.
예시: 비동기 API 처리, 여러 슬라이스가 동일 액션에 반응해야 할 때 등.
reducers는 해당 slice에서 만든 액션만 처리, extraReducers는 외부 액션도 처리 가능.
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
export const fetchData = createAsyncThunk('data/fetch', async () => { /* ... */ });
const dataSlice = createSlice({
name: 'data',
initialState: { value: null, loading: false },
reducers: {},
extraReducers: (builder) => {
builder
.addCase(fetchData.pending, (state) => { state.loading = true; })
.addCase(fetchData.fulfilled, (state, action) => { state.value = action.payload; state.loading = false; })
.addCase(fetchData.rejected, (state) => { state.loading = false; });
}
});
export const fetchData = createAsyncThunk('data/fetch', async () => { /* ... */ });
const dataSlice = createSlice({
name: 'data',
initialState: { value: null, loading: false },
reducers: {},
extraReducers: (builder) => {
builder
.addCase(fetchData.pending, (state) => { state.loading = true; })
.addCase(fetchData.fulfilled, (state, action) => { state.value = action.payload; state.loading = false; })
.addCase(fetchData.rejected, (state) => { state.loading = false; });
}
});
- 상태는 최대한 로컬로 관리 (필요할 때만 전역으로)
- 여러 컴포넌트가 공유해야 한다면 상태를 상위 컴포넌트로 올리거나 전역 상태 라이브러리 사용
- Context API는 소규모 전역 상태에만 (대규모는 Redux 등 추천)
- 불필요한 리렌더링 방지를 위해 useMemo, useCallback, React.memo 적극 활용
- 비동기 데이터는 React Query 등 서버 상태 관리 라이브러리로 분리
TIP.
전역 상태가 필요한 경우 Redux, Recoil, Zustand 등 라이브러리를 활용하고,
컴포넌트 내부 상태는 useState, useReducer로 관리하세요.
성능 최적화는 useMemo, useCallback, React.memo로 불필요한 리렌더링을 방지하는 것이 핵심입니다.
전역 상태가 필요한 경우 Redux, Recoil, Zustand 등 라이브러리를 활용하고,
컴포넌트 내부 상태는 useState, useReducer로 관리하세요.
성능 최적화는 useMemo, useCallback, React.memo로 불필요한 리렌더링을 방지하는 것이 핵심입니다.