Language/React.js

[React] TodoList 프로젝트 : useReducer 사용하기

JJcoding 2024. 10. 21. 09:41

useReducer

  • 컴포넌트 내부에 새로운 State를 생성하는 React Hook이다.
  • 모든 useState는 useReducer로 대체 가능하다.
  • 상태 관리 코드를 컴포넌트 외부로 분리할 수 있다.
  • UI를 렌더링하는 코드보다 상태를 관리하는 코드가 길어진다면 그것은 주객이 전도된 상황이다.
    그럴 때 useReducer 함수를 사용한다.

Exam.jsx

import { useReducer } from "react";

// reducer : 변환기
// -> 상태를 실제로 변화시키는 변환기 역할
function reducer(state, action) {
  //   if (action.type === "INCREASE") {
  //     return state + action.data;
  //   } else if (action.type === "DECREASE") {
  //     return state - action.data;
  //   }
  switch (action.type) {
    case "INCREASE":
      return state + action.data;
    case "DECREASE":
      return state - action.data;
    default:
      return state;
  }
}

const Exam = () => {
  // dispatch : 발송하다, 급송하다
  // -> 상태 변화가 있어야 한다는 사실을 알리는, 발송하는 함수
  const [state, dispatch] = useReducer(reducer, 0);

  const onClickPlus = () => {
    // 인수 : 상태가 어떻게 변화되길 원하는지
    // -> 액션 객체
    dispatch({
      type: "INCREASE",
      data: 1,
    });
  };

  const onClickMinus = () => {
    dispatch({
      type: "DECREASE",
      data: 1,
    });
  };

  return (
    <div>
      <h1>{state}</h1>
      <button onClick={onClickPlus}>+</button>
      <button onClick={onClickMinus}>-</button>
    </div>
  );
};

export default Exam;

  • reducer 안은 switch 문으로 하는 것이 일반적이다.
  • dispatch 함수안에 있는 객체를 액션 객체라고 한다. reducer 함수에서 action 매개변수로 받는다.

Todo List 업그레이드 하기

App.jsx

import "./App.css";
import Header from "./components/Header";
import Editor from "./components/Editor";
import List from "./components/List";
import { useRef, useReducer } from "react";

const mockDate = [
  {
    id: 0,
    isDone: false,
    content: "React 공부하기",
    date: new Date().getTime(),
  },
  {
    id: 1,
    isDone: false,
    content: "영어 공부하기",
    date: new Date().getTime(),
  },
  {
    id: 2,
    isDone: false,
    content: "독서하기",
    date: new Date().getTime(),
  },
];

function reducer(state, action) {
  switch (action.type) {
    case "CREATE":
      return [action.data, ...state];
    case "UPDATE":
      return state.map((item) =>
        item.id === action.targetId ? { ...item, isDone: !item.isDone } : item
      );
    case "DELETE":
      return state.filter((item) => item.id !== action.targetId);
    default:
      return state;
  }
}

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

  const onCreate = (content) => {
    dispatch({
      type: "CREATE",
      data: {
        id: idRef.current++,
        isDone: false,
        content: content,
        date: new Date().getTime(),
      },
    });
  };

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

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

  return (
    <div className="App">
      <Header />
      <Editor onCreate={onCreate} />
      <List todos={todos} onUpdate={onUpdate} onDelete={onDelete} />
    </div>
  );
}

export default App;

  • useReducer로 이벤트 헨들러 안에서는 dispatch만 사용하여 코드를 깔끔하게 정리할 수 있다.

 

출처 : 한입 크기로 잘라먹는 리액트