[TIL] React로 간단한 Todo 앱 만들기 - 1

Alex J. Lee·2021년 9월 27일
0

TIL

목록 보기
21/58

순서

  1. create-react-app으로 새로운 React 프로젝트 생성
  2. 프로젝트 초기화 (App.js, App.css 비우기)
  3. 레이아웃 구상
  4. 재사용되는 부분을 개별 컴포넌트로 분리 (TodoItem.js)
  5. JSX로 문서 구조 만들기
  6. 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;
profile
🦄✨글 잘 쓰는 개발자가 되기 위해 꾸준히 기록합니다 ✨🦄

0개의 댓글