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로 불필요한 리렌더링을 방지하는 것이 핵심입니다.
'React' 카테고리의 다른 글
| React에서 State와 Props의 차이점 (0) | 2025.06.22 | 
|---|---|
| react : useQuery 에서 key 가 의미하는 것 (0) | 2025.03.12 | 
| React 상태 관리 문제 해결 과정 (0) | 2025.03.07 | 
| React : useMemo로 성능 최적화하기 (0) | 2025.02.26 |