[TIL] React Todo List만들기..!!

대빵·2023년 11월 3일

React 입문주차 개인과제를 받았닷..!!

리액트로 투두리스트를 제작하는 프로젝트를 전달받았다..(점점..과제가 어려워지는건 기분탓인지)

필수 요구사항

  1. 제목과 내용을 입력하고, 추가하기버튼을 클릭하면 Working에 새로운 Todo가 추가되고 제목 input과 내용 input은 다시 빈 값으로 바뀌도록 구성해주세요.

  2. Todo의 isDone 상태가 true이면, 상태 버튼의 라벨을 취소, isDone이 false 이면 라벨을 완료 로 조건부 렌더링 해주세요.

  3. Todo의 상태가 Working 이면 위쪽에 위치하고, Done이면 아래쪽에 위치하도록 구현합니다.

  4. Layout의 최대 넓이는 1200px, 최소 넓이는 800px로 제한하고, 전체 화면의 가운데로 정렬해주세요.

  5. 컴포넌트 구조는 자유롭게 구현해보세요.

너무 처음부터 막막하다보니 일단 필요한것들을 메모장에 적어보았닷...!!

Input과 Button버튼이 있어야하고.. Input에 값을 입력하면 Button을 누르면 List에 값이 전달이 되어야하고 List에는..Working이랑 Done이 있어야해서 List에서 Working에 먼저 입력이 되고 버튼을 확인 버튼을 누르면 Done으로 이동할 수 있어야하고.. Done에서 취소 버튼을 누르면 Working으로 이동해야하고..

머리속에 어떻게 구현을 해야할지 생각을 먼저했다..(그래도 이번에는 어떻게 동작하는지 생각이란걸 해보았다.. 이게 맞는지는 잘 모르겠지만??)

App.jsx

import React from "react";

function App() {
  return (
    <>
      <h1>Todo</h1>
      제목 : <input></input>
      내용 : <input></input>
      <button>추가하기</button>
      <div>
        Working..!
        <ul>
          <li>
            <h3>제목</h3>
            <span>내용내용내용...</span>
            <div>
              <button>삭제</button>
              <button>완료</button>
            </div>
          </li>
        </ul>
      </div>
      <div>
        Done..!
        <ul>
          <li></li>
        </ul>
      </div>
    </>
  );
}

기본적으로 생각한 틀은 먼저 만들어 보았다..ㅎㅎ

틀은 만들었지만.. 이제부터가 기능을 넣을 차례이다ㅎㅎ

제일 첫번째는 input안에 입력을 하면, 값을 가지고오는게 첫번째 해야할 일이닷..ㅎㅎ

input value값

import React, { useState } from "react";

function App() {
  const [title, setTilte] = useState("");
  const [detail, setDetail] = useState("");

  return (
    <>
      <h1>Todo</h1>
      제목 :{" "}
      <input
        value={title}
        onChange={function (e) {
          setTilte(e.target.value);
        }}
      ></input>
      내용 :{" "}
      <input
        value={detail}
        onChange={function (e) {
          setDetail(e.target.value);
        }}
      ></input>
      <button>추가하기</button>
		.
        .
        .
        .
        .
    </>
  );
}

여기에서 input의 value값을 state를 통해서 상태변화가 이루어지다보니 각 input에다가 각 각의 state를 넣어서 값을 가져왔다

잘가지고 왔는지 확인은 필수..!!

console.log(title);
console.log(detail);

이때, title값과 setTilte중 왜...title값을 찍어야만 원하는 input의 value값을 확일할 수 있는지... 이유를 모르는 사람이 나뿐만 아닐거라고 믿고...ㅎㅎ

[state, setState] = useState(초기값)이 이렇게 있다고 생각하면 제가 생각한건 state는 초기값이고 setState는 변화되게 해주는 느낌이였는데 쉽고 간단하게 생각하면 state변수라고 생각하고 setState함수라고 생각하면 헷갈리지는 않을 것이다.

이제 input값의 value를 찾았으니 button을 누르면 value값을 Working에 표시되게 form태그를 이용해서 button을 클릭하면 Working에 필요하다

form태그 화면출력

  const Submit = function (e) {
    e.preventDefault();

    const newTodo = { title: title, detail: detail };

    // input에 아무것도 입력되지 않았을때 alert로 알려주는중...
    if (title === "") {
      return alert("제목이 비어있어요.");
    } else if (detail === "") {
      return alert("내용이 비어있어요.");
    }

    setTodo([...todo, newTodo]);

    // input의 value값 초기화
    setTilte(""); 
    setDetail("");
  };

  return (
    <>
      <h1>Todo</h1>
      <form onSubmit={Submit}>
        <input>
        <input>
        <button>추가하기</button>
      </form>
      <div>
        Working..!
        <ul>
          {todo.map((list) => {
            return (
              <li>
                <h3>{list.title}</h3>
                <span>{list.detail}</span>
                <div>
                  <button>삭제</button>
                  <button>완료</button>
                </div>
              </li>
            );
          })}
        </ul>
      </div>
    </>
  );
}

이제는 입력을 하면 Working에 잘 표시가 되는 것을 확인했으니.. 이제는!! 버튼에 삭제 기능을 넣어야할 차례이닷..!!

삭제버튼 기능

  // id값을 date로 설정
  const id = Date.now(); 

  const deletBtn = (id) => {
    setTodo(todo.filter((todo) => todo.id !== id));
  };

이제 마지막 과제인 완료버튼을 누르면 취소버튼으로 바뀌면서 Done으로 이동하고, 취소버튼을 누르면 완료 버튼으로 바뀌면서 Working쪽으로 옮겨지는것만 남았닷..!!

완료 -> 취소 | 취소 -> 완료

  const isDoneBtn = (id) => {
    setTodo(
      todo.map((todos) => {
        // todo.id값이 우리가 찾는 id값이 아니면 그냥 반환한다
        // todo.id값이 우리가 찾는 id값이라면 isDone 속성을 반대로 설정하고 반환한다.
        if (todos.id !== id) {
          return {
            ...todos,
          };
        } else {
          return {
            ...todos,
            isDone: !todos.isDone,
          };
        }
      })
    );
  };

  return (
      <div>
        Working..!
        <ul>
          {todo
            .filter((todo) => {
              return todo.isDone === false;
            })
            .map((list) => {
              return (
                <li>
                  <h3>{list.title}</h3>
                  <span>{list.detail}</span>
                  <div>
                    <button onClick={() => deletBtn(list.id)}>삭제</button>
                    <button onClick={() => isDoneBtn(list.id)}>
                      {list.isDone ? "취소" : "완료"}
                    </button>
                  </div>
                </li>
              );
            })}
        </ul>
      </div>
  );
}

역시.. 나머지들 기능들 중에서 제일 시간을 많이 쏟은 코드이닷.. 다른분들의 조언과 힌트를 얻고 어느정도 구현을 했는데... 그냥 id값을 찾으려했던 내 자신에 반성을 하면서.. 스프레드 문법으로해서 전체 todos의 객체를 가지고와서

완성코드

import React, { useState } from "react";

import "./App.css";

function App() {
  const [title, setTilte] = useState("");
  const [detail, setDetail] = useState("");

  const [todo, setTodo] = useState([]);

  const id = Date.now();

  const Submit = function (e) {
    e.preventDefault();

    const newTodo = { title: title, detail: detail, id: id, isDone: false };

    if (title === "") {
      return alert("제목이 비어있어요.");
    } else if (detail === "") {
      return alert("내용이 비어있어요.");
    }

    setTodo([...todo, newTodo]);

    setTilte(""); 
    setDetail("");
  };

  const deletBtn = (id) => {
    setTodo(todo.filter((todos) => todos.id !== id));
  };

  const isDoneBtn = (id) => {
    setTodo(
      todo.map((todos) => {
        if (todos.id !== id) {
          return {
            ...todos,
          };
        } else {
          return {
            ...todos,
            isDone: !todos.isDone,
          };
        }
      })
    );
  };

  return (
    <div className="App">
      <h1>Todo</h1>
      <form onSubmit={Submit}>
        제목 :
        <input
          value={title}
          onChange={function (e) {
            setTilte(e.target.value);
          }}
        ></input>
        내용 :
        <input
          value={detail}
          onChange={function (e) {
            setDetail(e.target.value);
          }}
        ></input>
        <button>추가하기</button>
      </form>
      <div>
        Working..!
        <ul>
          {todo
            .filter((todo) => {
              return todo.isDone === false;
            })
            .map((list) => {
              return (
                <li>
                  <h3>{list.title}</h3>
                  <span>{list.detail}</span>
                  <div>
                    <button onClick={() => deletBtn(list.id)}>삭제</button>
                    <button onClick={() => isDoneBtn(list.id)}>
                      {list.isDone ? "취소" : "완료"}
                    </button>
                  </div>
                </li>
              );
            })}
        </ul>
      </div>
      <div>
        Done..!
        <ul>
          {todo
            .filter((todo) => {
              return todo.isDone === true;
            })
            .map((list) => {
              return (
                <li>
                  <h3>{list.title}</h3>
                  <span>{list.detail}</span>
                  <div>
                    <button onClick={() => deletBtn(list.id)}>삭제</button>
                    <button onClick={() => isDoneBtn(list.id)}>
                      {list.isDone ? "취소" : "완료"}
                    </button>
                  </div>
                </li>
              );
            })}
        </ul>
      </div>
    </div>
  );
}

export default App;

이렇게 React기초 프로젝트 TodoList를 완성했지만 이제는 컴포넌트로 나누어서 props로 받는 방법을 정리해야한닷..!!

이번과제 쉽지만 쉽지않은... 그래도 많은것을 배우고 useState에 관해서 조금은 이해가 되는거 같다!!

0개의 댓글