[To-Do List] 제작 프로젝트 #1 - 프로젝트 개요 및 제작과정

G_NooN·2024년 1월 24일
0

프로젝트

목록 보기
7/13

프로젝트 개요

React로 To-Do List 만들기

예시

요구사항

  1. 제목과 내용을 입력하고 [추가하기] 버튼을 클릭 시, 새로운 Todo가 Working에 추가되고,
    제목/내용 입력창 내부는 빈 창으로 초기화

  2. Todo의 상태가 Working이면 위쪽에 위치하고, Done이면 아래쪽에 위치시킴

  3. Todo의 isDone 상태가 true면 상태 버튼의 라벨을 [취소]로 설정하고,
    Todo의 isDone 상태가 false면 상태 버튼의 라벨을 [완료]로 설정

  4. [삭제하기] 버튼 클릭 시, 해당 Todo를 삭제

  5. Layout의 최대 너비는 1200px, 최소 너비는 800px로 설정하고, 전체 화면의 가운데로 정렬

  6. 반복되는 컴포넌트는 분리


프로젝트 제작 과정

기본 TodoList 작성 및 레이아웃 설정

// App.jsx
function App() {
  const [todoList, setTodoList] = useState([
    {
      id: 1,
      title: "리액트 공부하기",
      content: "생각보다는 쉽지만 그래도 어려워요ㅠㅠ",
      isDone: false,
    },
    {
      id: 2,
      title: "휴식하기",
      content: "그런건 없음ㅠㅠ",
      isDone: true,
    }
  ]);
  
  return (
    <div className="layout">
    </div>
  )
}

export default App;
/* App.css */
.layout {
  min-width: 800px;
  max-width: 1200px;
  margin: 0 auto;
}

헤더 컴포넌트 제작

// App.jsx
return (
  <div className="header">
    <h3>My Todo List</h3>
    <h3>React</h3>
  </div>
);
/* App.css */
.header {
  display: flex;
  justify-content: space-between;
  padding: 0 20px;
}

Todo 추가 컴포넌트 제작

각 입력 값에 대한 state 생성

const [title, setTitle] = useState("");
const [content, setContent] = useState("");

각 입력 값에 대한 Event Handler 생성

const titleChangeHandler = (event) => {
  setTitle(event.target.value);
};
const contentChangeHandler = (event) => {
  setContent(event.target.value);
};

todo 추가 기능 생성

const addTodo = () => {
  const newTodo = {
    id: todoList.length + 1,
    title,
    content,
    isDone: false,
  };
  setTodoList([...todoList, newTodo]);
};

출력 구조

// App.jsx
return (
  <div className="add-todo">
    <div className="todo-info">
      <label className="form-title">제목</label>
  	  <input
        className="form-content"
        name="todo-title"
        value={title}
        onChange={titleChangeHandler}                                                 
      />
      <label className="form-title">내용</label>
  	  <input
        className="form-content"
        name="todo-content"
        value={content}
        onChange={contentChangeHandler}                                               
      />
  	</div>
    <button className="addBtn" onClick={addTodo}>
      추가하기
    </button>
  </div>
);
/* App.css */
.add-todo {
  display: flex;
  justify-content: space-between;
  padding: 20px;
  background-cooor: whitesmoke;
}
.form-title {
  font-weight: bold;
}
.form-content {
  width: 200px;
  margin: 0 20px;
  padding: 10px;
  border: none;
  border-rarius: 10 px;
}
.addBtn {
  width: 100px;
  border: none;
  border-radius: 10px;
  background-color: powderblue;
  font-weight: bold;
}

Todo 출력 컴포넌트 제작

todo 삭제 기능 생성

filter() 메서드를 사용하여 선택한 todo의 id와 일치하지 않는 todo를 새 todoList로 설정

const deletetodo = (id) => {
  const newTodoList = todoList.filter((todo) => todo.id !== id);
  setTodoList(newTodoList);
};

isDone 여부에 따라 버튼의 state 변경

map() 메서드를 사용하여 선택한 todo의 isDone 상태를 변경함

const checkTodoDone = (id) => {
  const newTodoList = todoList.map((todo) => {
    if(todo.id === id) {
      return {...todo, isDone: !todo.isDone};
    } else {
      return {...todo};
    }
  });
  setTodoList(newTodoList);
};

출력 구조

// App.jsx
return (
  <div className="todo-list">
    <div className="list-container">
      <h2>Working..</h2>
      <div className="working-list">
        {todoList
          .filter((todo) => !todo.isDone)
          .map((todo) => {
            return (
              <div key={todo.id} className="todo-item">
                <h3>{todo.title}</h3>
                <p>{todo.content]<p>
                <button className="removeBtn" onClick={() => deleteTodo(todo.id)}>
                  삭제
                </button>
                <button className="checkDoneBtn" onClick={() => checkTodoDone(todo.id)}>
                  {todo.isDone ? "취소" : "완료"}
                </button>
              </div>
            );
          })
        }
      </div>
    </div>
    <div className="list-container">
      <h2>Done!!</h2>
      <div className="done-list">
        {todoList
          .filter((todo) => todo.isDone)
          .map((todo) => {
            return (
              <div key={todo.id} className="todo-item">
                <h3>{todo.title}</h3>
                <p>{todo.content]<p>
                <button className="removeBtn" onClick={() => deleteTodo(todo.id)}>
                  삭제
                </button>
                <button className="checkDoneBtn" onClick={() => checkTodoDone(todo.id)}>
                  {todo.isDone ? "취소" : "완료"}
                </button>
              </div>
            );
          })
        }
      </div>
    </div>
  </div>
);
/* App.css */
.todo-list {
  padding: 20px;
}
.todo-item {
  margin: 20px;
  padding: 20px;
  border: 3px solid darkseagreen;
  border-radius: 10px;
}
.removeBtn,
.checkDoneBtn {
  width: 50px;
  height: 30px;
  margin-right: 10px;
}
.removeBtn {
  background-color: white;
  border: 3px solid red;
  border-radius: 10px;
}
.checkDoneBtn {
  background-color: white;
  border: 3px solid green;
  border-radius: 10px;
}

결과 화면

profile
쥐눈(Jin Hoon)

0개의 댓글