React.js

투두리스트로 간단하게 알아보는 useReducer

2025. 5. 13. 23:00

useReducer

먼저, useReducer는 어떤 역할을 하는지 간단히 정리하고 넘어가려 한다.

useReducer는 useState를 온전히 대체할 수 있는 메서드로,

useState로 관리되는 상태들은 모두 컴포넌트 내부에서만 관리되어야 하며, 관련 로직도 모두 컴포넌트 내부에서만 작성되어야 한다. 

때문에 UI 렌더링만 담당하면 되는 App 컴포넌트에서 굳이 노출될 필요 없는 로직들이 useState에 의해 모두 담겨있어야 하고, 이는 가독성과 유지보수성을 해친다. 

이렇게 useState로 인해 컴포넌트 내부 코드가 쓸데없이 복잡해질 경우, useReducer를 사용해서 상태 관리 함수들을 모두 외부로 분리하여 컴포넌트를 정리할 수 있다.

 

단, 그렇다고 해서 모든 state를 useReducer로 사용하면 오히려 코드가 더 복잡해질 수도 있다.

상황에 따라 간단하게 상태 처리를 할 수 있으면 useState를 쓰고, 

투두리스트처럼 상태 처리 로직이 복잡하고 가짓수가 많으면 useReducer를 쓰는 것이 좋다.

 

useState vs useReducer

조건 추천
상태가 단순하고 UI 요소 몇 개에만 영향을 줄 때 ✅ useState
상태가 복잡하고 관련 액션이 많을 때 ✅ useReducer
여러 개의 상태가 서로 연관되어 있을 때 ✅ useReducer
상태 변경 로직을 명확하게 분리하고 싶을 때 ✅ useReducer

 

 

useReducer 적용 전

  • 하나의 App 컴포넌트에서 투두 리스트의 create, update, delete 상태가 모두 useState로 관리되고 있으며,
  • 기능 로직도 모두 App 컴포넌트에서 쓰이고 있어 App 컴포넌트가 다소 복잡해진 상황이다.
// App.jsx
function App() {
  const [todos, setTodos] = useState(mockData);
  const idRef = useRef(3);

  const onCreate = (content) => {
    const newTodo = {
      id: idRef.current++,
      isDone: false,
      content,
      date: new Date().toLocaleString("ko-KR"),
    };

    setTodos((prevTodos) => [newTodo, ...prevTodos]);
  };

  const onUpdate = (targetId) => {
    setTodos(
      todos.map((todo) => {
        return todo.id === targetId ? { ...todo, isDone: !todo.isDone } : todo;
      })
    );
  };

  const onDelete = (targetId) => {
    setTodos(
      todos.filter((todo) => {
        return todo.id !== targetId;
      })
    );
  };

  return (
    <>
      <Header />
      <Editor onCreate={onCreate} />
      <List items={todos} onUpdate={onUpdate} onDelete={onDelete} />
    </>
  );
}

export default App;

App 컴포넌트에서는 UI들을 잘 렌더링 해주고, 자식 컴포넌트들에게 필요한 데이터들을 잘 전달해주기만 하면 되기 때문에 굳이 어떠한 기능의 로직까지 담고 있을 필요는 없다. 이런 경우에는 useReducer와 같은 방법을 사용해서 useState와 연계된 기능 로직들을 모두 외부로 분리시켜주는 것이 좋다.

 

 

useReducer 적용 후

// App.jsx
import { useRef, useReducer } from "react";
import todoReducer from "./reducer/TodoReducer";
// 포스팅과 관련없는 import들은 생략...

function App() {
  const [todos, dispatch] = useReducer(todoReducer, mockData); 
  const idRef = useRef(3);

  const onCreate = (content) => {
    dispatch({
      type: "CREATE",
      data: {
        id: idRef.current++,
        content,
        date: new Date().toLocaleString("ko-KR"),
      },
    });
  };

  const onUpdate = (targetId) => {
    dispatch({
      type: "UPDATE",
      targetId,
    });
  };

  const onDelete = (targetId) => {
    dispatch({
      type: "DELETE",
      targetId,
    });
  };

  return (
    <>
      <Header />
      <Editor onCreate={onCreate} />
      <List items={todos} onUpdate={onUpdate} onDelete={onDelete} />
    </>
  );
}

export default App;

기능 구현 로직들을 모두 외부 reducer 함수로 분리해서 useReducer로 갖다쓰니까 확실히 App 컴포넌트가 깔끔해졌고, 

각 기능별 코드도 더 직관적으로 바뀌었다. (어떤 기능을 하고, 어떤 인자들이 전달되는지 쉽게 파악 가능)

 

 

[외부 reducer 함수]

// todoReducer.js
export default function todoReducer(todos, action) {
  switch (action.type) {
    case "CREATE":
      return [action.data, ...todos];
    case "UPDATE":
      return todos.map((todo) =>
        todo.id === action.targetId ? { ...todo, isDone: !todo.isDone } : todo
      );
    case "DELETE":
      return todos.filter((todo) => todo.id !== action.targetId);
    default:
      throw new Error("Unknown action type: " + action.type);
  }
}

 

 

'React.js' 카테고리의 다른 글

[리액트] 같은 파일 재등록 안될 때 (등록 -> 삭제 -> 재등록)  (0) 2025.05.27
Navigate vs useNavigate  (0) 2025.05.15
함수형 업데이트와 클로저 이해하기 (심화)  (0) 2025.05.12
브라우저가 리액트를 실행하는 과정 (간단 요약)  (0) 2025.05.08
배열 state 변경할 때, Spread 문법을 써야 하는 이유 (중요)  (0) 2025.05.05
'React.js' 카테고리의 다른 글
  • [리액트] 같은 파일 재등록 안될 때 (등록 -> 삭제 -> 재등록)
  • Navigate vs useNavigate
  • 함수형 업데이트와 클로저 이해하기 (심화)
  • 브라우저가 리액트를 실행하는 과정 (간단 요약)
쥬피썬더의노예
쥬피썬더의노예
오히려 좋아
  • 쥬피썬더의노예
    d.log
    쥬피썬더의노예
    글쓰기 관리
    • 분류 전체보기 (112)
      • JS (37)
      • TS (3)
      • WEB (10)
      • React.js (20)
      • Next.js (4)
      • tanstack query (2)
      • Node.js (2)
      • HTML (5)
      • CSS (13)
      • CS (1)
      • 에이전트 (1)
      • Git (4)
      • JAVA (0)
      • SQL (0)
      • db (0)
      • GSAP (0)
      • 자료구조 (1)
      • 알고리즘 (0)
      • ✨회고 (5)
      • 포꾸 (0)
      • 인터뷰 (0)
      • 개발일지 (0)
      • 일기 (1)
      • etc (3)
      • 정처기 실기 (0)
        • C (0)
        • Java (0)
        • Python (0)
      • fonts (0)
      • articles (0)
      • 도서 (0)
  • 인기 글

  • 태그

    SSG
    React
    Next.js
    useState
    조합 패턴
    HTML
    React Query
    상태 관리
    프론트엔드
    state
    아키텍처
    폼
    javascript
    useEffect
    TypeScript
    CSR
    React.JS
    WEB
    zustand
    Til
    안티그래비티
    SSR
    GIT
    자바스크립트
    css
    슬라이딩 윈도우
    클로저
    유효성 검사
    리액트
    리팩토링
  • 최근 글

  • 전체
    오늘
    어제
  • hELLO· Designed By정상우.v4.10.3
쥬피썬더의노예
투두리스트로 간단하게 알아보는 useReducer
상단으로

티스토리툴바