본문 바로가기
Frontend/React

생활코딩 React useReducer 실습 정리

by 삐뚤비버 2025. 7. 27.

1. 핵심 개념 먼저 이해하기

개념  설명
state 컴포넌트의 상태, 예: 숫자, 문자열, 객체 등
action 어떤 일이 일어났는지 설명하는 객체 (예: { type: 'UP' })
dispatch 액션을 reducer에 보내는 함수
reducer 현재 상태(state)와 액션(action)을 받아서 새로운 상태를 반환하는 함수

비교 비유

방식  비유
useState 손님이 직접 장부에 기록
useReducer 손님이 창구에 주문 → 회계 담당자가 장부를 처리

2. 실습 단계별 요약

[A] useState로 카운터 만들기

목표: 버튼 3개 (-, 0, +)로 숫자 상태 변경

순서:

  1. useState로 count 상태 만들기
  2. 버튼 3개 만들기
  3. 버튼 클릭 시 count 변경 (setCount 호출)
  4. <span>{count}</span>으로 현재 값 출력

코드 요약:

const [count, setCount] = useState(0);
<button onClick={() => setCount(count - 1)}>-</button>
<button onClick={() => setCount(0)}>0</button>
<button onClick={() => setCount(count + 1)}>+</button>

문제점:

상태가 많아지면 setState 함수가 계속 늘어남. 상태 로직이 컴포넌트 안에 흩어짐


[B] useReducer로 리팩토링

목표: 상태 로직을 컴포넌트 밖 reducer로 분리

순서:

  1. useReducer import
  2. countReducer(state, action) 함수 작성
  3. useReducer(countReducer, 초기값) 호출 → [state, dispatch] 반환
  4. dispatch({ type: 'UP' }) 형식으로 상태 변경 요청
  5. 버튼 클릭 시 dispatch 호출

코드 요약:

function countReducer(state, action) {
  if (action === 'UP') return state + 1;
  if (action === 'DOWN') return state - 1;
  if (action === 'RESET') return 0;
}
const [count, dispatch] = useReducer(countReducer, 0);

[C] 액션을 객체로 확장 (유저 입력 수만큼 증감)

목표: 입력값만큼 count가 증가/감소하도록 개선

변경사항:

  • 액션을 문자열 대신 객체 { type: 'UP', number: 입력값 } 형식으로 전달
  • countReducer에서 action.number 사용

reducer 코드:

function countReducer(state, action) {
  if (action.type === 'UP') return state + action.number;
  if (action.type === 'DOWN') return state - action.number;
  if (action.type === 'RESET') return 0;
}

dispatch 호출 예:

dispatch({ type: 'UP', number: 3 });

3. 최종 전체 코드 정리

import React, { useReducer, useState } from "react";

export default function App() {
  const [number, setNumber] = useState(1);

  function countReducer(oldCount, action) {
    if (action.type === "UP") return oldCount + action.number;
    if (action.type === "DOWN") return oldCount - action.number;
    if (action.type === "RESET") return 0;
  }

  const [count, dispatch] = useReducer(countReducer, 0);

  function up() {
    dispatch({ type: "UP", number });
  }

  function down() {
    dispatch({ type: "DOWN", number });
  }

  function reset() {
    dispatch({ type: "RESET" });
  }

  function changeNumber(e) {
    setNumber(Number(e.target.value));
  }

  return (
    <div>
      <input type="button" value="-" onClick={down} />
      <input type="button" value="0" onClick={reset} />
      <input type="button" value="+" onClick={up} />
      <input type="number" value={number} onChange={changeNumber} />
      <span>{count}</span>
    </div>
  );
}

4. 이 실습의 핵심 포인트

포인트 설명

상태 로직 분리 reducer 함수로 상태 변경 로직을 컴포넌트 밖으로 분리함
액션 → 처리 흐름 버튼 클릭 → dispatch(action) → reducer에서 처리 → 새로운 state 반환
가독성 향상 상태가 많아질수록 useReducer 구조가 더 깔끔하고 유지보수 쉬움
추상화 상태 변경을 "업무 요청"처럼 처리 가능 (직접 변경이 아닌, 요청 기반 구조)

5. useReducer의 장단점 요약

항목 장점 단점

구조 상태 변경 로직이 분리돼서 깔끔함 단순한 로직에는 과할 수 있음
유지보수 액션 타입 중심으로 상태 흐름 추적 가능 액션 타입, reducer 작성 등 코드가 많아짐
확장성 상태가 많을수록 구조적으로 좋음 초보자에겐 처음엔 어려워 보일 수 있음

6. 언제 useReducer를 쓰면 좋을까?

  • 상태가 객체/배열처럼 복잡할 때
  • 상태 변경 조건이 많을 때 (if/switch 많은 경우)
  • 컴포넌트 안에 로직이 복잡하게 섞여 있을 때
  • 상태 로직을 재사용하거나 테스트하고 싶을 때

'Frontend > React' 카테고리의 다른 글

React Todo App 만들기 (Vite + useState + 데이터 흐름 이해)  (2) 2025.08.12
Vite와 Create React App(CRA) 비교  (1) 2025.08.11
React useReducer  (2) 2025.07.27
React State  (0) 2025.07.19
이벤트 핸들링  (1) 2025.07.19

me