← 홈페이지 5강 목록으로
🔁
EPISODE 04
action · dispatch · reducer · 불변성

useReducer

복잡한 상태 로직을 useState 대신 useReducer로 분리하기 — action/dispatch/reducer 패턴, useState와의 선택 기준, 그리고 불변성을 유지한 상태 업데이트.

ReactuseReducer불변성
소요 시간
45~60분
난이도
📊 중급
선수 조건
🎯 react-03
결과물
여러 상태가 얽힌 cart 같은 복잡 로직을 reducer로 분리

이 강의에서 배우는 것

  • 1action/dispatch/reducer 3요소를 안다
  • 2switch문으로 reducer를 작성한다
  • 3useState와 useReducer의 선택 기준을 안다
  • 4스프레드/map/filter로 불변성을 유지한다

1. 문법

jsx
const [state, dispatch] = useReducer(reducer, initialState);
요소역할
state현재 상태
dispatchaction을 보내는 함수
reducer(state, action) => newState 순수 함수
initialState초기 상태

2. action / dispatch / reducer

jsx
const ADD_ITEM = 'ADD_ITEM';
const REMOVE_ITEM = 'REMOVE_ITEM';
const CLEAR_CART = 'CLEAR_CART';

function cartReducer(state, action) {
  switch (action.type) {
    case ADD_ITEM:
      return { ...state, items: [...state.items, action.payload] };
    case REMOVE_ITEM:
      return { ...state, items: state.items.filter(i => i.id !== action.payload) };
    case CLEAR_CART:
      return { ...state, items: [] };
    default:
      return state;
  }
}

function Cart() {
  const [state, dispatch] = useReducer(cartReducer, { items: [] });

  const addItem = (product) => dispatch({ type: ADD_ITEM, payload: product });
  const removeItem = (id) => dispatch({ type: REMOVE_ITEM, payload: id });
}

3. useState vs useReducer

상황권장
단순한 값 하나useState
여러 state가 서로 연관useReducer
다음 상태가 이전 상태에 의존useReducer
상태 업데이트 로직이 복잡useReducer
테스트가 중요 (reducer는 순수)useReducer
jsx
// useState로 분산되면 복잡
const [items, setItems] = useState([]);
const [total, setTotal] = useState(0);
const [discountRate, setDiscountRate] = useState(0);
const [appliedCoupon, setAppliedCoupon] = useState(null);

// useReducer로 묶음
const [cartState, dispatch] = useReducer(cartReducer, {
  items: [], total: 0, discountRate: 0, appliedCoupon: null,
});

4. 불변성 유지

jsx
// ❌ 직접 변경 — 리렌더링 안 됨!
case ADD_ITEM:
  state.items.push(action.payload);
  return state;

// ✅ 새 배열 생성
case ADD_ITEM:
  return { ...state, items: [...state.items, action.payload] };

// ✅ 특정 항목 수정 — map으로 새 배열
case UPDATE_QUANTITY:
  return {
    ...state,
    items: state.items.map(item =>
      item.id === action.payload.id
        ? { ...item, quantity: action.payload.quantity }
        : item
    ),
  };

// ✅ 특정 항목 제거 — filter
case REMOVE_ITEM:
  return { ...state, items: state.items.filter(i => i.id !== action.payload) };
예제 코드 / 강의 자료

전체 강의 자료와 예제 코드는 GitHub에서 자유롭게 받아볼 수 있습니다.

GitHub에서 보기 ↗