개발하는 디자이너/04. 공부

[React] TODO 앱을 만들며 배우는 CRUD

Kila 2024. 11. 27. 16:31

React를 이용해 TODO앱을 만들어봅니다. 이를 통해 CRUD(Create / Read / Update / Delete) 기능이 작동되는 방식을 알 수 있습니다. 자신이 만든 앱을 공유하고 피드백을 기반으로 앱을 업그레이드하는 것을 포함합니다.

 

 

import { useState } from "react";
import "./App.css";

const initialTodos = [
  { id: 1, text: "운동가기", completed: false, dueDate: "2024-11-28" },
  { id: 2, text: "미션 완료하기", completed: true, dueDate: "2024-11-29" },
  { id: 3, text: "리액트 과제", completed: false, dueDate: "2024-11-28" },
];

function App() {
  const [todos, setTodos] = useState(initialTodos);
  const [input, setInput] = useState("");
  const [dueDate, setDueDate] = useState("");
  const [editingId, setEditingId] = useState(null); // 수정 중인 항목 ID

  // 섹션별 할 일 분류
  const groupByDate = todos.reduce((groups, todo) => {
    if (!groups[todo.dueDate]) {
      groups[todo.dueDate] = [];
    }
    groups[todo.dueDate].push(todo);
    return groups;
  }, {});

  // 할 일 추가
  function handleAddTodo() {
    if (!input.trim()) {
      alert("할 일을 입력하세요!"); // 입력값이 비어있을 때
      return;
    }
    if (!dueDate.trim()) {
      alert("날짜를 선택하세요!"); // 날짜가 비어있을 때
      return;
    }

    if (editingId) {
      // 수정 모드
      setTodos(
        todos.map((todo) =>
          todo.id === editingId ? { ...todo, text: input, dueDate: dueDate } : todo
        )
      );
      setEditingId(null); // 수정 모드 해제
    } else {
      // 새 항목 추가
      const newTodo = {
        id: Date.now(),
        text: input,
        completed: false,
        dueDate: dueDate,
      };
      setTodos([...todos, newTodo]);
    }
    setInput(""); // 입력 초기화
    setDueDate(""); // 날짜 초기화
  }

  // 수정 모드 활성화
  function handleEdit(todo) {
    setInput(todo.text);
    setDueDate(todo.dueDate);
    setEditingId(todo.id);
  }

  // 상태 변경
  function toggleCompletion(id, status) {
    setTodos(
      todos.map((todo) =>
        todo.id === id ? { ...todo, completed: status } : todo
      )
    );
  }

  // 할 일 삭제
  function handleDelete(id) {
    setTodos(todos.filter((todo) => todo.id !== id));
  }

  return (
    <div className="App">
      <h1>Todo App</h1>
      <div className="input-section">
        <input
          type="text"
          value={input}
          onChange={(e) => setInput(e.target.value)}
          placeholder="Add a new task"
        />
        <input
          type="date"
          value={dueDate}
          onChange={(e) => setDueDate(e.target.value)}
        />
        <button onClick={handleAddTodo}>
          {editingId ? "Update" : "Add"}
        </button>
      </div>
      <div className="todo-list">
        {Object.keys(groupByDate).map((date) => (
          <section key={date}>
            <h2>{date}</h2>
            <ul>
              {groupByDate[date].map((todo) => (
                <li key={todo.id} className="todo-item">
                  <div className="todo-details">
                    <span className={todo.completed ? "completed" : ""}>
                      {todo.text}
                    </span>
                    <div className="todo-actions">
                      <label>
                        <input
                          type="radio"
                          name={`status-${todo.id}`}
                          checked={todo.completed}
                          onChange={() => toggleCompletion(todo.id, true)}
                        />
                        완료
                      </label>
                      <label>
                        <input
                          type="radio"
                          name={`status-${todo.id}`}
                          checked={!todo.completed}
                          onChange={() => toggleCompletion(todo.id, false)}
                        />
                       미완료
                      </label>
                      <button onClick={() => handleEdit(todo)}>수정</button>
                      <button onClick={() => handleDelete(todo.id)}>삭제</button>
                    </div>
                  </div>
                </li>
              ))}
            </ul>
          </section>
        ))}
      </div>
    </div>
  );
}

export default App;

 

 

728x90