[TIL]レスポンスを使用した簡単なTodoアプリケーション-1の作成



オーダー

  • create-act-appを使用して新しいreactプロジェクト
  • を作成
  • プロジェクト初期化(App.js、App.cssをクリア)
  • レイアウト構想
  • 繰り返し使用する部分を単一の要素(TooItem.js)
  • に分離する
  • JSXを使用して文書構造
  • を作成
  • inputとbuttonに適切なイベントハンドラ関数
  • を追加

    App.js

    import React, { useState } from "react";
    import { nanoid } from "nanoid"; // id를 생성해주는 package
    import "./App.css";
    import TodoItem from "./components/TodoItem";
    
    function App() {
      // task : input에서 입력받은 task 내용
      const [task, setTask] = useState("");
      // todoList : 화면에 보여질 전체 task를 모은 배열
      const [todoList, setTodoList] = useState([]);
    
      // input에 onChange 이벤트가 일어났을 때,
      const handleInputText = (event) => {
        // input의 value로 task를 업데이트
        setTask(event.target.value);
      };
    
      // 추가 버튼에 onClick 이벤트가 일어났을 때,
      const handleAddBtn = (event) => {
        // 새로운 todo 객체를 생성
        const todo = {
          id: nanoid(),
          isChecked: false,
          task: task,
        };
        // 새로운 todo를 담아 todoList 배열 업데이트
        setTodoList([todo, ...todoList]);
        // 다음 task를 받기 위해 현재 task를 비워줌
        setTask("");
      };
      
      // input에서 Enter를 눌렀을 때,
      const handleKeypress = (event) => {
        if (event.key === "Enter") {
          handleAddTodo();
        }
      }
    
      // checkbox에 onChange 이벤트가 일어났을 때,
      const handleCheckbox = (id) => {
        // 해당 todo의 id를 인자로 받음
        // 해당 id를 가진 요소의 isChecked 값을 반전한 새로운 배열로 todoList를 업데이트
        const idx = todoList.findIndex((el) => el.id === id);
        const newTodoList = [...todoList];
        newTodoList[idx] = {
          ...todoList[idx],
          isChecked: !todoList[idx].isChecked,
        };
        setTodoList(newTodoList);
      };
    
      // 삭제 버튼에 onClick 이벤트가 일어났을 때,
      const handleDeleteBtn = (id) => {
        // 해당 todo의 id를 인자로 받음
        // 해당 id를 가진 요소를 todoList에서 제외한 새로운 배열로 todoList를 업데이트
        const idx = todoList.findIndex((el) => el.id === id);
        const newTodoList = [...todoList];
        newTodoList.splice(idx, 1);
        setTodoList(newTodoList);
      };
    
      return (
        <div className="App">
          <header>
            <h1>TODO</h1>
          </header>
          <main>
            <div className="task-input-wrapper">
              <input
                className="task-input-text"
                value={task}
                type="text"
                placeholder="Add task"
                onChange={handleInputText}
                onKeyDown={handleKeypress}
              />
              <button className="task-input-btn" onClick={handleAddBtn}>
                <i className="fas fa-plus"></i>
              </button>
            </div>
            <div>
              <ul>
                {todoList.map((el) => (
                  <TodoItem
                    todo={el}
                    handleCheckbox={handleCheckbox}
                    handleDeleteBtn={handleDeleteBtn}
                  />
                ))}
              </ul>
            </div>
          </main>
        </div>
      );
    }
    
    export default App;

    TodoItem.js

    import React from 'react';
    import './TodoItem.css';
    
    const TodoItem = ({ todo, handleCheckbox, handleDeleteBtn }) => {
      return (
        <li id={todo.id}>
          <input type="checkbox" checked={todo.isChecked} onChange={() => handleCheckbox(todo.id)} />
          <span className={todo.isChecked ? "task-content checked" : "task-content"}>{todo.task}</span>
          <button className="task-delete-btn" onClick={() => handleDeleteBtn(todo.id)}><i className="far fa-trash-alt"></i></button>
        </li>
      )
    };
    
    export default TodoItem;